LINUXMAKER, OpenSource, Tutorials

Configuration of DNSSEC on BIND9

Setting up DNSSEC is to be demonstrated here in BIND9 on a Debian Linux system. Provided that a functioning DNS BIND server already exists as described here.


All configuration files for Bind9 are in "/etc/bind/", on RedHat, Centos and Fedora Linux systems the filing structure is somewhat different from Debian. And the zone files are generally below "/var/cache/bind/" structured according to the TLD in their own directories such as "de", "com" etc.

Zone Walking and NSEC3

Zone walking (DNSSEC walking or zone enumeration) is known as a method by which attackers can read out the complete content of DNSSEC-signed DNS zones. In this way, confidential data (such as customer lists) and security-relevant information (server IP addresses) can be tapped.
DNSSEC automatically chains all labels in a ring in alphabetical order when signing a zone using NSEC Resource Records. It looks like this using the example of the zone example.tld
    example.tld. NSEC name1
    name1         NSEC name2
    name2         NSEC name5
    name5         NSEC example.tld.

On the left is the label (canonical name) and on the right a reference to the next lexographic label. In this way, the non-existence of names can be proven. So if a client asks for the non-existent name name3, then the DNS server replies with the NSEC entry name2 NSEC name5 and thus signals that there is no further entry between name2 and name5. The attacker takes advantage of this chaining by starting with the first name of a zone (this is always the name of the zone itself) and running through the chain through successive queries. Thanks to this technically quite simple process, he can read out the entire zone content within a few seconds.

Defense with NSEC3

Zone walking makes it significantly more difficult with the alternative to NSEC, namely NSEC3. NSEC3 no longer displays the names in plain text, but as a cryptographic hash value. Although NSEC3 makes zone walking more difficult, attacks on the hash function cannot completely avoid zone walking. Therefore the following configuration should be done with NSEC3.


First, here is the view of DNSSEC, KSK, ZKS and RRSIG.

For each zone that is to be secured, a separate zone key (zone signing key) consisting of a public and a private key is generated. The public part of the ZSK then exists in the respective zone file as a DNSKEY resource record. With the private key, however, each individual RR in the zone is then digitally signed.

In addition to the key for the signature of the zone (ZSK), a syntactically identical key signature key KSK (Key Signing Key) is generated. The background to this is the fact that the zone keys (DNSKEY) can change more often and, in the case of a chain of trust, the parent zone would no longer trust the child zone. However, since in this case the KSK remains the same for a long period of time, the chain of trust between the parent and child zones is retained in the event of changes. Otherwise, the child zone would have to continuously provide the parent zone with new keys, which can be very inefficient and prone to errors.

Ultimately, the zone is signed using the DNSKEYs, while the resource records are signed using the RRSIGs.

Generate key signing key (KSK)

For the sake of better structuring, we first create a new directory within the Bind9 configuration directory.

mkdir -p /etc/bind/keys/
chown -R bind:bind /etc/bind/keys/

The KSK is generated within this new directory with the following command:

dnssec-keygen -3 -a RSASHA512 -b 4096 -n ZONE -r /dev/urandom -f KSK example.tld

  • -3 activates the desired NSEC3
  • -a determines the type of signature
  • -b indicates the desired block size
  • -n specifies the name type such as ZONE, HOST, USER
  • -f this flag must be set especially for KSK

There are now two files in the directory:

  • Kexample.tld.+010+64413.key (DNSKEY Record),
    which serves to verify the ZSKs and is signed by higher zones.

  • Kexample.tld.+010+64413.private,
    the private key to the signature of the public ZSK.

The DNSKEY record in the public key looks something like this:

cat Kexample.tld.+010+64413.key
; This is a key-signing key, keyid 64413, for example.tld.
; Created: 20200313175118 (Fri Mar 13 18:51:18 2020)
; Publish: 20200313175118 (Fri Mar 13 18:51:18 2020)
; Activate: 20200313175118 (Fri Mar 13 18:51:18 2020)
example.tld. IN DNSKEY 257 3 10 AwEAAaoJiFk+Xj+9v[...]KTMN4QNqRm8l1RgnDq/2GvrxmSPXfGKyWm fjvSJot4EX2i97ER

Generate Zone Signing Key (ZSK)

The zone signing key is then generated as follows, followed by a reassignment of the file attributes.

dnssec-keygen -3 -a NSEC3RSASHA1 -b 2048 -n ZONE -r /dev/urandom example.tld
chown -R bind:bind /etc/bind/keys/

Now there are two more files in the directory:

  • Kexample.tld.+007+40385.key,
    the public key (DNSKEY record), which is used to verify the DNS responses.
  • Kexample.tld.+007+40385.private,
    the private key for signing the resource records.

The content of this ZSK is roughly as follows.

cat Kexample.tld.+007+40385.key
; This is a zone-signing key, keyid 40385, for example.tld.
; Created: 20200313175211 (Fri Mar 13 18:52:11 2020)
; Publish: 20200313175211 (Fri Mar 13 18:52:11 2020)
; Activate: 20200313175211 (Fri Mar 13 18:52:11 2020)
example.tld. IN DNSKEY 256 3 7 AwEAAauXGNQMitXTRPKAkme9[...]Mqi3ZvO 0yn19+nxfb8=

Sign the zones yourself

Now the zone in the respective zone file can be prepared for the signature by adding the public key using the $ INCLUDE directive. On the one hand, this can be easily done using a loop

for key in `ls Kexample.tld.*.key`
echo "\$INCLUDE /etc/bind/keys/$key">> /var/cache/bind/tld/db.example.tld

or individually per zone file with a vi function:

:r! ls /etc/bind/keys/Kexample.tld.*.key

Signing creates a new zone file with the suffix ".signed".

dnssec-signzone -3 `head -c 512 /dev/urandom | sha1sum | cut -b 1-16` -z -H 330 -K /etc/bind/keys -t -o example.tld /var/cache/bind/tld/db.example.tld

Verifying the zone using the following algorithms: NSEC3RSASHA1 RSASHA512.
Zone fully signed:
Algorithm: NSEC3RSASHA1: KSKs: 0 active, 0 stand-by, 0 revoked
                         ZSKs: 1 active, 0 stand-by, 0 revoked
Algorithm: RSASHA512: KSKs: 1 active, 0 stand-by, 0 revoked
                      ZSKs: 0 active, 0 stand-by, 0 revoked
Signatures generated:                       26
Signatures retained:                         0
Signatures dropped:                          0
Signatures successfully verified:            0
Signatures unsuccessfully verified:          0
Signing time in seconds:                 0.315
Signatures per second:                  82.418
Runtime in seconds:                      0.358

chown -R bind:bind  /var/cache/bind/

However, it should now be noted that after every change in the zone file, it must also be re-signed.
In addition, the signed zones are only valid for 30 days by default. You can give dnssec-signzone your own end date for the validity of the signed zone file with "-e YYYYMMDDHHMMSS".

Activate DNSSEC in BIND9

In the global options of BIND9 you activate DNSSEC with the following entries in /etc/bind/named.conf.options

dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;

key-directory "/etc/bind/keys/";

In the file /etc/bind/named.conf.local you only change the file of in the zone declarations

zone "example.tld" {
        type master;
        file "tld/db.example.tld";
        allow-transfer {
        notify yes;


zone "example.tld" {
        type master;
        file "tld/db.example.tld.signed";
        allow-transfer {
        notify yes;

and restart the BIND9

systemctl restart bind9.service

Provide the DNSSEC key to the registrar

Finally, the DNSSEC must be activated with your own registrar. This happens on their web portals by entering the DNSKEY RR to match the zone and also DS Record. To do this, wait until the AXFR of the registrar's name server has taken place and a positive query

dig DNSKEY example.tld

returns the DNSKEY. Then you know that the zones have synchronized. The DNSSEC is displayed for both the zone key (256) and the key signature key (257). The registrar must be entered with the flag 257. In addition, the delegation signer record (DS-RR) - this contains the digest of the KSK public key - must be entered. The latter is in an additional file "dsset-example.tld." in the directory from which you started "dnssec-signzone", the contents of which can be adopted:

cat dsset-example.tld.

example.tld.            IN DS 40385 7 1 CDD805F6E544091910FF821AEB6D83756F02A23E
example.tld.            IN DS 40385 7 2 75D763812727198BD0B5FD4F5FCA59B96262D0EF390A435829FC66E8 9492D462
example.tld.            IN DS 64413 10 1 43DF817F6558611A58617C8017338F76E6015AE5
example.tld.            IN DS 64413 10 2 096EEEFF5E66BA5DC03930D3A567BE57247FEDDFBAFB5142508B24CB B2B153F8

Testing the DNSSEC

If you now query the DNS server or other name servers, provided that you have already activated the DNSSEC with your registrar, you will get this information.

dig example.tld dnskey +noall +answer +multiline

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> example.tld dnskey +noall +answer +multiline
;; global options: +cmd
example.tld.            86400 IN DNSKEY 257 3 10 (
                                ) ; KSK; alg = RSASHA512 ; key id = 64413
example.tld.            86400 IN DNSKEY 256 3 7 (
                                ) ; ZSK; alg = NSEC3RSASHA1 ; key id = 40385

If you use the +dnssec option in dig, the RRSIG records are also displayed:

dig A www.example.tld +dnssec

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> A www.example.tld +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45983
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 7, ADDITIONAL: 2
;; WARNING: recursion requested but not available
; EDNS: version: 0, flags: do; udp: 4096
; COOKIE: e6717cb28dcc8637149ebe435e6f790ddf6237e8cfc03713 (good)
;www.example.tld.               IN      A
www.example.tld.        86400   IN      A
www.example.tld.        86400   IN      RRSIG   A 7 3 86400 20200415110953 20200316110953 40385 example.tld. DYnaFMQaVpOO3VA8ZYg7K3YKHMgl4+UFLXjgUt35GLYLrUwO5XKQwr+T LKlBukkIgC2zUVVZSuIGoDv8rDGCeBED2d0KrnVjdQjqS00ZUOCGUU27 vagd/u6DuHUF0VVWgHU8fjWG1+S4rqRov3pSQ0gCq5JaYFOZZXeKCcq4 cmcL/9dQbdL5h1JArqxJoNtQOnlKw7JtifWAHRtWPX7eQ4tbq6TA9fR3 SQ/nde4ZP6dRDyv2OcO3lpfhc/JDbeyksu11nfp8WLjjDTsY5D2mC4bA a0kL9H357OiKtLiwLSCOM/zYa/gq+2wUDOSnG/zX7jfKvDr+rQWKcAvV l1/apg==
www.example.tld.        86400   IN      RRSIG   A 10 3 86400 20200415110953 20200316110953 64413 example.tld. kCA+W2mn/Hvgx50L51DJzMqRluiYp/m2Gb8DLHqNmu7kSNmFYmpq+jvk caEcBroZaoyalsGAFJas+NlYHQGZFyzJKav1dujb0I8nUDsG7TGnmH70 lVpP6qqvo2pveZYeq50q7BKt49mIoEiYMbFyGW4i6oR0w+ueshb/BgqN FlMzDOk99aKRBwV+JmxImcVKZIfYtQ/Q7z20z7rZVBUcL9yUsCSo7J4N OmABeSxwH2Y63eChTDCuFfy5ngnCD+Iqr2HT9X+Y2oz7g3hsuUPP9PHD s4ingQo+aQ2PPzO6endmwsq27XBJ8M0jurEA2oSmoj4d5qZvcknlJ/Us YIZmF8Q/uKSqg9Z4wF+okYo/meC3wRtdsDWoW7irO47Ion0whVvj16X8 fiVn9eHBa1SNf+D+EpRRog8dlEuaK2ScFJDVdzx4JX3ps9b1hVPqlpPa b1uMYRQJpKfc2IZjwkiAcwcTW95tasuvpg8t1ZUOHgumf2f7eS5VwLsv cR2GRn+NGO9o9TrjYRddArSkodDecOY0Ac4OEgq2allTTw7IPMYabyXz 5UzVKQVJ2NXfvZyfR000yf1etx2jXcdB7yBXcTyfyE+C+sUIB72d5TKg z+/bcO/7Zgryp9ixvwM/qFexFqYHD5WuEuAbOGf1sq7gZF2HxnCK+DuI Swpt61A34V0=

he DNSSEC configurations can also be checked online. For example the DNSSEC debugger from Verisign Labs.