HOWTO
DNS
NOTES ON DNSSEC ON BIND

Published: 20211124

Tested on: BIND 9.10.3 (Ubuntu Server 16.04.7 ESM stock)

-

Assuming you already have BIND setup for your domain:

Generate your private keys, the KSK (Key Signing Key) and the ZSK (Zone Signing Key).
It might be a good thing noting down which was which, hence the NFO-file I create.

# cd /etc/bind
# dnssec-keygen -f KSK -a ECDSAP256SHA256 -n ZONE example.com.
Generating key pair.
Kexample.com.+013+41016
# echo KSK > Kexample.com.+013+41016.nfo
# dnssec-keygen -a ECDSAP256SHA256 -n ZONE example.com.
Generating key pair.
Kexample.com.+013+05820
# echo ZSK > Kexample.com.+013+05820.nfo
#

Another way of knowing which is which, is to check the KEY-files that holds the DNSKEY strings.
"IN DNSKEY 257" = KSK, "IN DNSKEY 256" = ZSK.

Add the public KSK and the public ZSK to your zone (domain):

# cd /etc/bind
# cat Kexample.com.+013+41016.key >> /etc/bind/master/example.com.zone
# cat Kexample.com.+013+05820.key >> /etc/bind/master/example.com.zone
#

Sign the zone:

# cd /etc/bind
# dnssec-signzone -o example.com. -f master/example.com.zone.signed -k Kexample.com.+013+41016 master/example.com.zone
Verifying the zone using the following algorithms: ECDSAP256SHA256.
Zone fully signed:
Algorithm: ECDSAP256SHA256: KSKs: 1 active, 0 stand-by, 0 revoked
                            ZSKs: 1 active, 0 stand-by, 0 revoked
master/example.com.zone.signed
#

Change the named.conf settings from the unsigned file to the signed file:
(This is in /etc/bind/named.conf or /etc/bind/named.conf.local)

zone "example.com" {
        type master;
        file "/etc/bind/master/example.com.zone.signed";
};

Reload the settings:

# rndc reload

Your zone is now signed and active. You can check with:

$ dig +dnssec @localhost example.com. DNSKEY
; <<>> DiG 9.10.3-P4-Ubuntu <<>> +dnssec @localhost example.com. DNSKEY
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7465
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;example.com.           IN  DNSKEY
;; ANSWER SECTION:
example.com.        21600   IN  DNSKEY  256 3 13 GRCzcC0BMGfn+Fe9YQGk+QCKoUg2nS6RrZORPkZKsiTEKEW8GWLK2PbD qSTDGhrH+fx8ZNS5BE5xQtNI/LpoOA==
example.com.        21600   IN  DNSKEY  257 3 13 PGZMM0IxUKg8J2Qdy4CHgrTlRyH+dOC9HD2stF7k+r3FA44lvgi9E9F+ gKMvl++KJRILikv2CPo9+xGyrjTMqA==
example.com.        21600   IN  RRSIG   DNSKEY 13 2 21600 20211223205049 20211123205049 5820 example.com. 6WkqVznfMCLRYRZzCHnE/PaP8WRw0BaMUFGNOeKxX8W1eK7HgJNWj+nj Hj4jcs+y0T9cwID8rXv9I8myhawkkg==
example.com.        21600   IN  RRSIG   DNSKEY 13 2 21600 20211223205049 20211123205049 41016 example.com. r+xBgx5+QbWjgqTPDiBkc86PwcPyI1UMbI5irlD8sv9SSZVmeSCtVmiF 0O8gzyXcrQ0YLdomnlGS3EYkkKqJaw==
;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Tue Nov 23 23:46:52 CET 2021
;; MSG SIZE  rcvd: 414
$

The KSK needs to be "uploaded" to the registry/TLD that holds your domain.
In this case it means that we provide our registrar of the domain with the DS record that corresponds to our KSK DNSKEY record. (Almost like a "DNSKEY GLUE record" if you will.)

Here's the line to give our registrar:

# cd /etc/bind
# dnssec-dsfromkey -2 Kexample.com.+013+41016
example.com. IN DS 41016 13 2 BF04D5F2EBD589B6B46C5C46D3EF5361DB7715711ECA720C63CF491B06C2983B
#

Another way of formatting the values:

When the registrar has configured the registry with the DS records and the settings have reached everyone's DNS caches, you can verify with:

$ dig +dnssec @<registry-NS> example.com. DS

Alternatively you can use the program called "delv":

$ delv example.com SOA

Important
Let's review the RRSIG lines from the command above:

$ dig +dnssec @localhost example.com. DNSKEY | grep RRSIG
example.com.        21600   IN  RRSIG   DNSKEY 13 2 21600 20211223205049 20211123205049 5820 example.com. 6WkqVznfMCLRYRZzCHnE/PaP8WRw0BaMUFGNOeKxX8W1eK7HgJNWj+nj Hj4jcs+y0T9cwID8rXv9I8myhawkkg==
example.com.        21600   IN  RRSIG   DNSKEY 13 2 21600 20211223205049 20211123205049 41016 example.com. r+xBgx5+QbWjgqTPDiBkc86PwcPyI1UMbI5irlD8sv9SSZVmeSCtVmiF 0O8gzyXcrQ0YLdomnlGS3EYkkKqJaw==
$
                                                          ^^^^^^^^^^^^^^
                                                          this value [*]

[*] this value 20211223205049 is the "Signature Expiration" timestamp: 2021-12-23 20:50:49

You need to constantly keep this value fresh; so that DNSSEC enabled resolvers are happy and you wont get warnings and complaints from everywhere.

This is done by:

# cd /etc/bind
# dnssec-signzone -o example.com. -f master/example.com.zone.signed -k Kexample.com.+013+41016 master/example.com.zone
# rndc reload
#

You can either do it with a crontab script at least once a month or by using scripts that automate this.

There's supposed to be automation in newer versions of BIND, but the reports differ on how well it works.