Skip to main content

DNSSEC bind9


Part 1 - DNSSEC Validation

Part 2 - DNSSEC Signing for Forward Zone

Part 3 - Secure Delegation and Key Rollover


DNSSEC Diagram


For reference, these are the IP address assignments for the servers:



Part 1 - DNSSEC Validation

For this part, you will configure and explore a DNSSEC-validating resolver, which automatically validates DNS answers from an authoritative server.

There are 2 steps in this part:
  • Step 1 - Verify DNS
  • Step 2 - DNSSEC Validation

Step 1 - Verify DNS

The two servers in this lab have BIND9 already installed and pre-configured as a Resolver.

1. Select primarydns which we will be using for this step. Login to the machine.

username: username
password: passowrd

2. Check where BIND is installed and note the version.

which named
named -v 

It should show that named is in /usr/sbin/named and running BIND version 9.18.30 for Ubuntu 22.04.

3. Check if BIND is running.

ps aux | grep named

There should be a process with /usr/sbin/named -u bind.

Check systemd to confirm that you see the status as active (running).

ps aux | grep named
sudo systemctl status named

If not, then run the name daemon

sudo systemctl start named

4. Check the configuration file.

cd /etc/bind/
sudo more /etc/bind/named.conf.local

There are three zones already defined - one for the forward domain herdiansah-lab.xyz, another two for reverse domain 163.209.85.in-addr.arpa and 194.105.109.in-addr.arpa. This will be used in the next part.

5. Also check the logs and notice if there are any errors. Open a new tab in the Terminal, and run the command:

sudo tail -f /var/log/named/bind.log

The zone files should load correctly with no issues.

Keep checking your log file after editing your config or if you restarted the BIND service. This is a good way to spot errors and fix them.

6. Do the same steps above for the secondarydns. Make sure to confirm that BIND is running without errors.

cd /etc/bind/
sudo more named.conf.local
sudo systemctl status named

7. Use dig utility to resolve domains.

dig google.com
dig @localhost google.com

Step 2 - DNSSEC Validation

Now that you are familiar with the lab setup and DNS is running, we can proceed with DNSSEC.

DNSSEC validation is enabled by default in BIND, which allows it to validates responses from authoritative servers automatically.

1. From primarydns, check that dnssec-validation is enabled in the configuration file.

cd /etc/bind/
sudo more /etc/bind/named.conf.options | grep dnssec-validation

Within the options statement, confirm that dnssec-validation is set to auto.

options {
      ...
      dnssec-validation auto;
      ...
}

If you need to update, open the file and update accordingly.

sudo vi named.conf.options

There are 3 possible values to use for dnssec-validation: | Value | Definition | |:---------|:-----------------| | **auto** | DNSSEC validation is enabled and a default trust anchor for the DNS root is used, provided as part of BIND. | | **yes** | DNSSEC validation is enabled and a trust anchor must be manually configured using the 'trust-anchors' statement | | **no** | DNSSEC validation is disabled |

2. Trust Anchor.

A validating resolver requires at least one trust anchor to be able to validate.

The default value is 'auto', which is used in most production setup. With this, the default root key stored in bind.keys file is used which is already included with BIND.

There is no need to modify this file. Check the contents.

sudo more /etc/bind/bind.keys




Here is the format of the trust-anchors statement. Note that the inital-key modifier means it is trusted only once to initially load the managed key database.

trust-anchors {
      . initial-key 257 3 8 "some-key"; 
};

Any further updates will be read from the managed-keys.bind file.

sudo more /var/cache/bind/managed-keys.bind

Notice the key identifier for root key (key ID 20326).

If DNSSEC-validation is set to yes, a custom trust anchor must be defined manually using a **trust-anchors** statement in the config file. A `static-key` modifier is used instead of `initial-key` so it is always trusted.

3. Update the logging statement to channel DNSSEC-related logs into another log file.

sudo vi /etc/bind/named.conf.options

channel dnssec_log {
       file "/var/log/named/dnssec.log" versions 3 size 5m;
       severity info;
       print-time yes;
       print-severity yes;
       print-category yes;
};

Update the category for dnssec to push logs into the channel just created.

category dnssec { dnssec_log; };

This means the logs related to DNSSEC will be stored into the file dnssec.log.

Create this file and set the right permissions.

cd /var/log/named/
sudo touch dnssec.log
sudo chown bind.bind dnssec.log

Reload the configuration to apply the changes.

sudo rndc reconfig

4. Open the secondarydns and apply similar updates.

Check that dnssec-validation is set to auto.

sudo more /etc/bind/named.conf.options | grep dnssec

Update the logging statement to create a channel for DNSSEC logs.

sudo vi /etc/bind/named.conf.options

channel dnssec_log {
        file "/var/log/named/dnssec.log" versions 3 size 5m;
        severity info;
        print-time yes;
        print-severity yes;
        print-category yes;
};

Update the category for dnssec to push logs into the channel just created.

category dnssec { dnssec_log; };

Create this file and set the right permissions.

cd /var/log/named/
sudo touch dnssec.log
sudo chown bind.bind dnssec.log

Check and verify the config file for any syntax errors.

named-checkconf /etc/bind/named.conf

Reload the BIND configuration

sudo rndc reconfig

5. Use the dig utility to query.

Test a signed domain and confirm that the resolver is validating.

dig @localhost apnic.net +dnssec +multi

The output should include an A record and an RRSIG record. The RRSIG record holds the digital signature that is used to verify the A record.



Notice the 'AD' flag is set in the output. The AD bit means data is authenticated by the resolver.

For more detail about the information returned from the dig command refer to: * RFC1035 - 4.1.1. Header section format [https://www.rfc-editor.org/rfc/rfc1035](https://www.rfc-editor.org/rfc/rfc1035) * RFC6895 - 2. DNS Query/Response Headers [https://www.rfc-editor.org/rfc/rfc6895](https://www.rfc-editor.org/rfc/rfc6895)





6. Try to query a domain that is not DNSSEC-validating.

The domain dnssec-failed.org is explicitly failing validation, so this should result in SERVFAIL status.

dig @localhost www.dnssec-failed.org 



SERVFAIL error is generic. To confirm that this is a validation error, try the +CD option (checking disabled).

dig @localhost www.dnssec-failed.org A +cd

There should be an output record.




7. Another way to confirm this is to disable DNSSEC-validation.

Edit named.conf.options again and set dnssec-validation to no. Save and restart BIND.

sudo vi /etc/bind/named.conf.options

dnssec-validation no;

Reload the config.

sudo rndc reconfig
sudo rndc reload

Execute the dig query.

dig @localhost www.dnssec-failed.org A

Part 2 - DNSSEC Signing for Forward Zone

To allow a validating resolver to verify DNS record, the zone must be signed by the authoritative nameserver. Through DNSSEC Zone Signing, signatures are added to DNS as RRSIG records. In this part, you will sign the forward zone using a Fully-automated Key and Signing Policy (KASP).

There are 3 steps in this part:
  • Step 1 - Default DNSSEC policy
  • Step 2 - Custom DNSSEC policy

Step 1 - Default DNSSEC policy

DNSSEC policy defines the parameters for a fully-automated way of signing and maintaining zones, also called Key and Signing Policy (KASP).

1. Open primarydns. Before proceeding, disable or stop BIND.

sudo systemctl stop named

2. Create a DNSSEC policy for our forward zone.

There are 3 built-in policies: | Policy | Definition | |:---------|:-----------------| | **DEFAULT** | using the default policy | | **INSECURE** | used to gracefully unsign a zone | | **NONE** | no DNSSEC policy and the zone is not signed |

Use the default policy.

sudo vi /etc/bind/named.conf.local

Update the zone statement for zone herdiansah-lab.xyz by adding these two lines:

dnssec-policy default;
inline-signing yes;

The dnssec-policy statement requires dynamic DNS or inline-signing enabled.

The zone statement should look like this:

zone herdiansah-lab.xyz {
       <some-other-config>
       dnssec-policy default;
       inline-signing yes;
}

The default policy creates a single key and uses the following default parameters: * Algorithm: ECDSAP256SHA256 * Signing key: Combined Signing Key (CSK) * Key lifetime: unlimited * Proof of non-existence: NSEC

3. The zonefile also needs to be writeable by user BIND, so it's best to move the zonefile to the default directory for dynamic authoritative zones /var/lib/bind or add a symlink to point to the location of the file in /etc/bind/master.

And a symlink as follows:

cd /var/lib/bind
ln -s /etc/bind/master/db.herdiansah-lab .

Update the zone statement again to update the directory

sudo vi /etc/bind/named.conf.local

The zone statement should look like this:

zone herdiansah-lab.xyz {
       type master;
       file "/var/lib/bind/db.herdiansah-lab";
       dnssec-policy default;
       inline-signing yes;
}

4. Start BIND with the new configuration file.

Check for any syntax error then restart BIND.

named-checkconf /etc/bind/named.conf
sudo systemctl start named

Check the logfile to see DNSSEC-related logs

sudo tail -f /var/log/named/bind.log
sudo tail -f /var/log/named/dnssec.log

5. Check that the key files are created automatically.

Go to the working directory and list the files.

cd /var/cache/bind
ls -alh



There should be 3 files added.

Kherdiansah-lab.xyz.+013+39689.key
Kherdiansah-lab.xyz.+013+39689.private
Kherdiansah-lab.xyz.+013+39689.state

What is the Key ID? @lab.TextBox(keyid_csk)

First, check the content of the private key

sudo more Kherdiansah-lab.xyz.+013+39689.private

Then check the corresponding public key.

sudo more Kherdiansah-lab.xyz.+013+39689.key

Also check the metadata. This includes information on timing parameters - when the key is created, published, activated - among others.

Aside from the keypair, BIND also maintains a state file to track key timing parameters.

sudo more Kherdiansah-lab.xyz.+013+39689.state

Notice that both KSK and ZSK are set to yes. This means a combined signing key (CSK) is used.

6. Check the temporary files created after signing.

ls -alh /var/lib/bind

Find the files ending in .jnl, .jbk, or .signed

The following temporary files are created with inline-signing: | Filename | Purpose | |:-------|:---------| | db.herdiansah-lab.signed | all records from the zonefile including signatures | | db.herdiansah-lab.signed.jnl | working data for the signing process | | db.herdiansah-lab.jbk | journal backup file |

7. Compare the filesize of the original zonefile and the signed zonefile.

stat /etc/bind/master/db.herdiansah-lab | grep Size
stat /var/lib/bind/db.herdiansah-lab.signed | grep Size

8. Check secondarydns.

The secondary DNS pulls the signed zone file.

ls -alh /var/cache/bind/slave/db.herdiansah-lab

Notice the file size is the same as the file from the primary nameserver.

9. Verify DNSSEC.

Use dig to query the primarydns.

dig @85.209.163.249 herdiansah-lab.xyz +dnssec +multi

Use dig to query the secondarydns

dig @109.105.194.68 herdiansah-lab.xyz +dnssec +multi

In addition to the A record, the output also shows an RRSIG record (Resource Record Signature).

Step 2 - Custom DNSSEC policy

For the most part, a default policy is sufficient. However, if you want to customise the key parameters, you can create a custom DNSSEC policy.

1. Open primarydns. Stop named and clean up old files before updating the policy.

sudo systemctl stop named

Delete the previous CSK key files:

cd /var/cache/bind/
rm -rf Kherdiansah-lab.xyz.*

2. (Optional) Revoke any previously generated keys that will not be used further.

sudo dnssec-revoke Kherdiansah-lab.xyz.+013+<key-ID>.key

Replace the with the actual ID you wish to revoke.

3. Update the configuration file to use a custom policy.

sudo vi /etc/bind/named.conf.options

Add the following dnssec-policy statement at the end of the file.

dnssec-policy standard {
       dnskey-ttl 600;
       keys {
              ksk lifetime 365d algorithm ecdsap256sha256;
              zsk lifetime 30d algorithm ecdsap256sha256;
       };
       max-zone-ttl 600;
       parent-ds-ttl 600;
       parent-propagation-delay 2h;
       publish-safety 7d;
       retire-safety 7d;
       signatures-refresh 5d;
       signatures-validity 15d;
       signatures-validity-dnskey 15d;
       zone-propagation-delay 2h;
};




This new policy sets a separate Key and Zone Signing Keys (KSK and ZSK). You may also customise the other values, such as TTL and signature validity.

Check for any syntax error.

named-checkconf /etc/bind/named.conf

4. Restart BIND after the changes

sudo systemctl start named

Check for any DNSSEC-related errors in the logs:

sudo tail -f /var/log/named/bind.log
sudo tail -f /var/log/named/dnssec.log

5. Explore the keys

Go to the working directory.

cd /etc/bind/keys
ls -alh

Notice that there are two sets of keys created.

ls -alh

Open each file as needed and identify the KSK and ZSK key files.

What is the keyID for the Zone Signing Key (ZSK)?

@lab.TextBox(keyid_zsk)

What is the keyID for the Key Signing Key (ZSK)?

@lab.TextBox(keyid_ksk)

6. Use dig to verify DNSSEC.

Use dig to query the primarydns.

dig @85.209.163.249 herdiansah-lab.xyz +dnssec +multi

Use dig to query the secondarydns

dig @109.105.194.68 herdiansah-lab.xyz +dnssec +multi

The output should show an RRSIG record.

Part 3 - Secure Delegation and Key Rollover

After the zone is signed in Part 2, it is also required to establish the chain of trust from the parent zone. The parent zone must have a copy of the the zone's public key using the Delegation Signer or DS Record.

Step 1 - DS Record

1. Open the primarydns.

For the purposes of this lab, we will use a KSK (key ID 22956) that has been generated prior and has been preloaded to the parent.

This key is stored in the keys folder. Copy this over to the working directory.

cd /etc/bind/keys/
sudo cp Kdnslab.apnictraining.net.+013+22956* /var/cache/bind/

Or update the key-directory to point to the keys folder.

sudo vi /etc/bind/named.conf.options

Add the following line in the options statement.

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

2. (Optional) Revoke any previously generated keys that will not be used further.

sudo dnssec-revoke Kherdiansah-lab.xyz.+013+<key-ID>.key

Replace the <key-id> with the actual ID you wish to revoke.

After this step, notice the Inactive date in the .key file has been updated to current date. Also notice the Removed date has been updated in the .state file.

3. Generate the DS record from the public key.

dnssec-dsfromkey Kherdiansah-lab.xyz.+013+39689.key

The output should be a DS record

herdiansah-lab.xyz. IN DS 39689 13 2 3F487CD1395DB49F4B1C24224130701217F550732843431B909DBE2F55235C28

4. Use the new key to sign DNS records.

sudo rndc reconfig
sudo rndc reload

Confirm that you are using the key to sign the zone.

dig dnskey herdiansah-lab.xyz

Here is another command to generate the DS keys from a dig output.

dig @localhost dnskey herdiansah-lab.xyz | dnssec-dsfromkey -f - herdiansah-lab.xyz

Step 2 - Confirm DNSSEC

1. From the primarydns, first verify the DS record in the parent zone.

Typically, the generated DS record needs to be sent to the parent and added to the herdiansah-lab.xyz zone. This part is already done for you.

Confirm that the DS record is in the parent.

dig ds herdiansah-lab.xyz +trace

2. Use dig to query adding the +dnssec option.

dig @localhost herdiansah-lab.xyz +dnssec +multi

3. Use dig to trace the dig query from root to your primary server.

dig herdiansah-lab.xyz +dnssec +multi


4. Check for the AD bit from the flags in the dig response.

The AD flag means Authenticated Data, which is used in DNSSEC to indicate that the data is verified.

Step 3 - Key Rollover

DNSSEC keys need to be rolled over regularly. Here are the steps to do ZSK and KSK rollover.

1. For automated signing, ZSK Rollover is automatically performed using the key lifetimes specified in the dnssec policy.

Try to find the active DNSKEY records for the forward zone.

dig @localhost dnskey herdiansah-lab.xyz

If you see two ZSKs using the same algorithm, this usually means the rollover process is ongoing.

If key lifetime is set to unlimited, no rollover will be scheduled. For example, if you are using the default dnssec-policy in Part 2 Step 1, the lifetime is unlimited:

keys {
       csk key-directory lifetime unlimited algorithm ecdsa256;
};

2. For automated signing, KSK and CSK Rollover are also done automatically. However, the new DS record needs to be submitted to the parent zone.

This can be done automatically using the parental-agents block to update delegation information.

Alternatively, use RNDC to check the DS uploaded to the parent.

rndc dnssec -checkds -key 22956 published herdiansah-lab.xyz

The output will indicate the KSK is marked as published

KSK 39689: Marked DS as published since 26-Aug-2025 15:15:07.000



Step 4 - Algorithm Rollover

Algorithm rollover is required when moving to a more secure DNSSEC algorithm. For example, from Type 8 (RSASHA256) to Type 13 (ECDSASHA256).

When using dnssec-policy, this is automatically maanged by named process.

1. Create a new dnssec-policy using DNSSEC algorithm Type 15 (Ed25519). Also enable NSEC3.

Type 15 or Ed25519 is currently the recommended algorithm for DNSSEC signing. ``` sudo vi /etc/bind/named.conf.options ``` ``` dnssec-policy custom { dnskey-ttl 600; keys { csk lifetime 365d algorithm ed25519; zsk lifetime 30d algorithm ed25519; }; nsec3param; max-zone-ttl 600; parent-ds-ttl 600; parent-propagation-delay 2h; publish-safety 7d; retire-safety 7d; signatures-refresh 5d; signatures-validity 15d; signatures-validity-dnskey 15d; zone-propagation-delay 2h; }; ```

Update the zone statement for the forward zone to use the new policy.

sudo vi /etc/bind/named.conf.local

zone herdiansah-lab.xyz {
       ...
       dnssec-policy custom;
};

Check for any syntax errors, then load the new config.

named-checkzone /etc/bind/named.conf
sudo rndc reconfig
sudo rndc reload

2. Check for the new keys generated.

sudo ls -alh /var/cache/bind

Find the new key files created in the key-directory.

ls -alh  /var/cache/bind/Kherdiansah-lab.xyz.+013+*



Check if the new key is now used. Because of TTL and key rollover, this may not show instantly.

dig @localhost dnskey herdiansah-lab.xyz

Comments