How to: Deploying DNSSEC with BIND and Ubuntu Server

By on 23 May 2019

Category: Tech matters

Tags: , , ,


Blog home

Domain Name System Security Extensions (DNSSEC) enable the validation of DNS responses by authenticating the communication between DNS servers. This means that users can trust that the DNS responses they receive match the contents of the authoritative zone file.

This post is a quick step-by-step introductory to deploying DNSSEC.

In this tutorial, we will be using BIND on an Ubuntu Server. We will be using the following zone information:

Zone name/domain:
Zone file:

Note: At the time of writing, BIND 9.10.x has reached End-of-Life (EOL). It is recommended you use the current stable versions (BIND 9.12.4-P1 or BIND 9.14.1). For the purposes of this tutorial, we will keep using v9.10.3 since Ubuntu ships with it by default — the command and syntax should be the same.

Part 1: DNSSEC validation for end-users

This is for end-users, service providers and anyone running a recursive or caching resolver.

  1. Enable DNSSEC
    Open /etc/bind/named.conf.options and add:

    dnssec-enable yes;
    dnssec-validation auto;

    Note that dnssec-enable is already set by default, and you may choose not to explicitly add it in the config.

    If dnssec-validation is set to auto, it defaults to the DNS root zone as the trust anchor. BIND includes a copy of the root key which is kept up to date automatically. If set to yes, a trust anchor must be explicitly configured using the managed-keys or trusted-keys option.

  2. Test if it is validating
    Using the dig command:

    dig @localhost

    You can replace with the signed domain.

    dig @localhost +dnssec +multiline
    ; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost +dnssec +multiline
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53884
    ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
    ; EDNS: version: 0, flags: do; udp: 4096
    ; IN A
    ;; ANSWER SECTION: 300 IN CNAME 300 IN RRSIG CNAME 8 3 300 (
    20190608045355 20190509035355 43023
    5GQ+2ryIMY0aQFdQzufnHkGHMlqJM6fbHdREwPY= ) 300 IN A 300 IN A 300 IN RRSIG A 13 6 300 (
    20190510112012 20190508092012 34505
    dJdT3SF0lTKQ0oawaTuSyQjp3Zkwluo3J7/+SnwcHw== )
    ;; Query time: 2705 msec
    ;; SERVER:
    ;; WHEN: Thu May 09 20:20:12 AEST 2019
    ;; MSG SIZE rcvd: 396

    Notice that every answer has a corresponding signature (RRSIG record.)

    A validated response should have the AD (Authenticated Data) bit flag set and the header will have the status: NOERROR.

    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47652
    ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

    A response that is not validated will not have AD bit flag set and the HEADER status will be SERVFAIL.

    ;; >>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 21978
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

Part 2: DNSSEC signing for domain owners

This is usually for registries and hosting providers, or any user who owns a domain.

2.1 Generate key pair for ZSK and KSK

First, let’s generate the Zone Signing Key (ZSK). The syntax is as follows:

dnssec-keygen -a <ALGORITHM> -b <BITS> -n ZONE <ZONENAME>

Replace ALGORITHM, BITS, and ZONENAME. If not specified, the default values are RSASHA1 for the algorithm (-a), and a keysize (-b) of 1024 for ZSK and 2048 for KSK.

For the examples, let’s use as our zone. If you want to keep this default, the command will simply be:


If you plan to run this in a test environment, make sure to add source of randomness (-r). Otherwise, it will take a long time to generate the keys.

Let’s use a more secure algorithm and longer bits to generate ZSK. The command will be as follows:

dnssec-keygen -r /dev/urandom -a RSASHA256 -b 1024 -n ZONE

Here’s the expected output:

dnssec-keygen -r /dev/urandom -a RSASHA256 -b 1024 -n ZONE
Generating key pair..................++++++ .......++++++

Optional: If you choose to use elliptic curve for the algorithm, the ‘-b’ option is not necessary.

dnssec-keygen -r /dev/urandom -a ECDSAP256SHA256

Next, we generate the Key Signing Key (KSK). The command is very much the same, with a couple of adjustments:

  1. Specify that it’s the KSK
  2. Increase the key size.
dnssec-keygen -r /dev/urandom -a RSASHA256 -b 2048 -fKSK -n ZONE
Generating key pair....+++ .+++
$ more 
; This is a key-signing key, keyid 50539, for
; Created: 20190509104232 (Thu May  9 20:42:32 2019)
; Publish: 20190509104232 (Thu May  9 20:42:32 2019)
; Activate: 20190509104232 (Thu May  9 20:42:32 2019) IN DNSKEY 257 3 8 AwEAAarP/lL9Qt2zqFX/NHKBsX2EVZBx8oMIFw/ON8ij5sIpZyIvgLxR aoH/TdJiw8Y9WkXlCSr0IGHM3kooE
OsTgC+FBD0sZqCTxQW1tQQLgkHS /4tyglSihcuyC5mL8N77I1BqgHnou3eBeJV0rNogTHs5tkP0Ed4j98pc vBPtpekMHyftbucK8E0JWKfhahZqebS5N
rKp56YueaNc9w31jslTh7xM pMKlwSLIrNB28fcP1/azPcvF7rFhYJuwk1iFOime4LUdVxTY/UCSPi+m pd4iuEUskoraHMsmbN+jj+orNEMjxNoKeBZoX
hwcHPJ09scnhSTAKtjA fovltMH2WM0=

You should now have four files in the directory. One key pair (.key and .private) for the ZSK and another pair for the KSK.

Note: There are two possible keys to use for KSK — RSASHA256 and ECDSAP256SHA256. We have used the first one for this guide. Otherwise, ECDSAP256SHA256 is the recommended value.

2.2. Signing the zones

BIND supports three methods for signing zones: manual signing, auto-dnssec, and inline signing. We will look at both manual and automated options.

  1. Manual signing
    Manual zone signing is done using the dnssec-signzone command.
    Let’s first examine the content of the keyfiles.

    ls -alh /etc/bind/keys/
    more /etc/bind/keys/

    Notice the format of the file name is K<zonename>.+<algorithm-number>+<keyid>.key

    The .key file is the public key. Copy or reference the public keys for ZSK and KSK into your zone file. Let’s include the public DNSKEY in the zone file as follows:

    $INCLUDE “keys/” #myzsk
    $INCLUDE “keys/” #myksk

    Now we can sign the zone using the secret keys. Here is the syntax:

    dnssec-signzone -o <zonename> -N INCREMENT -t -k <KSK> <zonefile> <ZSK>

    For our example, the command should be:

    dnssec-signzone -o -N INCREMENT -t -k \

    This generates a file with the signed data. If you wish to name it something else, use the -f flag.

    Examine this signed file. Notice that the file is bigger and now contains new records created after signing (RRSIG, DNSKEY, NSEC).

    Next is publishing the zone. Reconfigure BIND to load the signed zonefile.

    To do this, edit the configuration file and point to the signed zone.

    vi named.conf.local
    zone “” {
                            type master;
                            #file “”;
                            file “”;
  2. Automatic signing
    The other method is using automatic signing. Update the configuration as follows to add the last three lines:

    vi named.conf.local
    zone “” {
                            type master;
                            file “/etc/bind/”;
                            key-directory “/etc/bind/keys”;
                            auto-dnssec maintain;
                            inline-signing yes;

    Note: The key-directory is the location of the KSK/ZSK keys. The BIND user must have ‘read’ access to this, so update your permissions accordingly.

    auto-dnssec has two options — allow or maintain.

    • auto-dnssec allow searches the key directory and signs the zone with the corresponding keys once it receives the command rndc sign.
    • auto-dnssec maintain does as above but also periodically checks the key directory.

    Using Remote Name Daemon Control (RNDC), we can then apply the updated config done above, and load the keys from the given directory.

    rndc reload
    rndc reconfig
    rndc loadkeys

    Then sign the zone using the following command:

    rndc signing -list

2.3: Chain of trust

To establish the chain of trust, we will then need to update the parent zone with the hash of our public key. This is called the Delegation Signer (DS).

If you used manual signing in Part 2.2, then the DS record should already be generated. Check for the two files starting with dsset-<xxx>. That should contain the two DS records that should be sent to your upstream.

If you used automatic signing, you will have to generate the DS record using the following command:

dig @localhost dnskey | dnssec-dsfromkey -f –

Then send the DS records to your parent zone. The parent zone (usually your hosting provider) generally has a portal where this can be uploaded. For reverse DNS, this can be done by updating the domain whois object using MyAPNIC.

2.4: Guard against zone walking with NSEC3

The steps above generate NSEC records. NSEC has been known to be susceptible to ‘zone walking’ attacks. That is, an attacker can find all the information in your zone by ‘walking’ it. NSEC3 provides a solution which makes it really hard (but not impossible) to do this attack.

So, for this section, let’s redo Parts 1 to 3, but instead using NSEC3. The update commands are as follows:

First, generate keys.

dnssec-keygen -r /dev/urandom -a RSASHA256 -3 -b 1024 -n ZONE
dnssec-keygen -r /dev/urandom -f KSK -a RSASHA256 -b 2048 -3 -n ZONE

Then randomly generate a number up to 2^31 and represent as 8 Hexadecimal digits. This is your salt.

openssl rand -hex 4

Load the keys and sign them.

rndc loadkeys
rndc signing -NSEC3PARAM 1 0 10 <some-salt>

Get the DS record.

dig @localhost dnskey | dnssec-dsfromkey -f –

Finally, upload to your parent zone.

Learn more via our webinar

There’s more to DNSSEC that we are unable to discuss in here (like key re-signing and rollover). To learn more, attend the free APNIC Academy DNSSEC Webinar.

For the complete reference on configuring DNSSEC in BIND, see ISC’s guide [PDF 2.2MB].

Rate this article

The views expressed by the authors of this blog are their own and do not necessarily reflect the views of APNIC. Please note a Code of Conduct applies to this blog.


  1. Nico Vink

    I’m using Ubuntu 18.04. Then Part 1 is wrong. Not the file /etc/bind/named.conf.local should be altered, but the file /etc/bind/named.conf.options In that file is allready the dnssec-validation auto; line, and you should put the line dnssec-enable yes; above that one. Thanks for the info.

  2. Nico Vink

    rndc reload
    rndc reconfig
    rndc loadkeys

    I cant make “rncd loadkeys” work on Ubuntu 18.04.
    Even when running as root you’ll get the error rndc: ‘loadkeys’ failed: permission denied

    Skipping those 3 rndc lines above and using 1 line containing e.g. “rndc reload” gives the feedback “zone reload up-to-date” so i guess that does the trick.

    And users need to open port 53 and 953 on UFW and their routers for the UDP/TCP protocol.

  3. Barbe

    Hello everyone. I tried to write a script to automate DNSSEC configuration. But I have troubles including keys in files.

    #sudo echo “\$INCLUDE /etc/bind/K$nom_zone.*.key” >>/etc/bind/db.$nom_zone
    #sudo echo “\$INCLUDE /etc/bind/K$nom_inv.*.key” >>/etc/bind/db.$nom_inv

    #sudo chown root:bind $key_zone1
    #sudo chown root:bind $key_zone2
    #sudo chown root:bind $key_inv1
    #sudo chown root:bind $key_inv2

    sudo mv $key_zone1.key zone_ksk.key
    sudo mv $key_inv1.key inv_ksk.key
    sudo mv $key_inv2.key inv_zsk.key
    sudo mv $key_zone2.key zone_zsk.key

    #sudo chown root:bind K$nom_zone.*.key
    #sudo chown root:bind K$nom_inv.*.key

    sudo echo “$INCLUDE $INCLUDE zone_ksk.key” >> /etc/bind/db.$nom_zone
    sudo echo “$INCLUDE $INCLUDE zone_zsk.key” >> /etc/bind/db.$nom_zone
    #sudo echo $key_zone2 >> /etc/bind/db.$nom_zone

    sudo echo “$INCLUDE $INCLUDE inv_ksk.key” >> /etc/bind/db.$nom_inv
    sudo echo “$INCLUDE $INCLUDE inv_zsk.key” >> /etc/bind/db.$nom_inv
    #sudo echo $key_inv2 >> /etc/bind/db.$nom_inv

    Here are some ways I used to include keys inside files. But none of these worked.
    Who can help me find a solution


Leave a Reply

Your email address will not be published. Required fields are marked *