Enabling DNSSEC on BIND

My previous post was an overview of DNSSEC and how it secures DNS transactions. This one covers how to enable DNSSEC on zones running on the BIND DNS server. Specifically, this example will involve setting up DNSSEC on a parent and child zone, and confirming successful operation.

An important concept to grasp is that BIND sort of takes on two different roles pertaining to DNSSEC. One is that of providing signed data for a zone for which it is authoritative. The other is that of a validating resolver for external zones. If you only want to set up your BIND server as a DNSSEC validating resolver and not sign any of your own zones, you can skip down to the “Resolver Validation” section.

The majority of this post’s content will be the actual instructions for enabling DNSSEC (the “how”), and very little explanation (the “why”). My preferred way of learning usually consists of diving in head first and tinkering, and then once I’m familiar enough, going back and learning the intricacies, and that’s how I’ll write this. There are links at the end of the post should you want more thorough documentation. I also suggest reading my previous DNSSEC 101 post if you haven’t already. Some of the steps in the post involve editing important configuration files, so as a precaution I recommend creating a backup copy of any file before editing it.


The requirement for signing a zone with BIND is at least version 9.3; I’m using v9.4 here. Bind v9.6 supports NSEC3 records, but I won’t be going over that. An important thing to be aware of is that a DNS server acting as a resolver will not validate data from a zone for which it is authoritative. The data is coming from the server’s own local disk, so is considered valid. This means if you follow along with this, you’ll need at least two BIND installations, one authoritative server for the zones, and one resolver for confirming operation.

Another requirement is the installation of OpenSSL libraries, which are needed for DNSSEC signing. If you compile BIND yourself it should be compiled with openssl support. Installation of this software is beyond the scope of this article, but a good package manager is always helpful. Exercises here are done using SuSE Linux Enterprise Server 10 with the YaST package management software. This example starts off assuming a correctly installed basic BIND 9.4 setup, with two zones configured: example.com & child.example.com.


The first prerequisite is to DNSSEC enable the server by editing the named.conf file. Add the following entry to the options section of the file, then restart BIND:

dnssec-enable yes;

Before signing a zone, you need to make a decision regarding what signing algorithm and key strength you will use. The currently supported algorithms are RSA/MD5, RSA/SHA1, and DSA. The most widely used is RSA/SHA1; it’s also recommended in RFC’s and U.S. government guides. The next choice to make is key size.  I generally use 1024 bits for a zone signing key (ZSK), and 2048 bits for the key signing key (KSK). Your choice can depend on several factors, RFC 4641 has some recommendations for choosing a key size. Generating the keys can take a while depending on system resources, so for testing purposes you may want to use the smallest size of 512 bits.


As discussed in the DNSSEC 101 post, the first step in signing is to generate two key pairs for the zone, the ZSK (signs the zone) & KSK (signs ZSK). This is done using the dnssec-keygen BIND utility. Following along with this example, to create a ZSK for the example.com domain with the RSA/SHA1 algorithm, and a key size of 1024 bits, the following command is run (run from the directory housing the zone files, on SuSE this is /var/lib/named/master):

dnssec-keygen -a RSASHA1 -b 1024 -n ZONE example.com

When this completes, two new files will have been created: Kexample.com+<alg>+<id>.key (the public key) & Kexample.com+<alg>+<id>.private (the private key). Next, to create the 2nd key pair, the KSK with a 2048 bit key size, run this command:

dnssec-keygen -a RSASHA1 -b 2048 -n ZONE -f KSK example.com

This will create two additional files with the same naming format. Now the public key portion of the ZSK and KSK need to be added to the zonefile. This enables validators to retrieve the keys. The easiest way to do that is to just pipe the contents of the files into the zonefile, using the following command (good time to make sure you have a backup):

cat Kexample.com+*.key >> example.com

You should now be able to see two new records in the zonefile, of type DNSKEY. After restarting BIND, you should also be able to query for these new records:

dig @localhost example.com DNSKEY

At this point, go back through the entire process in this section to generate keys for the child.example.com zone, making sure to replace “example.com” with “child.example.com” in all of the commands.


With the steps above completed, the zones are now ready to be signed, a process done with the dnssec-signzone command. In this case, the child.example.com zone needs to be signed first, I’ll describe why shortly. To sign the zone, run this command:

dnssec-signzone -N INCREMENT child.example.com

The -N option updates the SOA serial number (note this option isn’t supported with BIND 9.3). When this completes you will have 3 new files: dsset-child.example.com, keyset-child.example.com, and child.example.com.signed. The child.example.com.signed file is the new zonefile, with records canonically ordered and new RRSIG & NSEC records added. Take note of the size difference compared to the original zone file. The dsset file is the Delegation Signer (DS) record for the zone, which needs to be added to the parent zone in order to facilitate chain-of-trust validation. This is the reason we signed the child zone first, if the parent zone was first, it would have to be re-signed after adding the DS record.

To add a DS record for the child zone into the parent zone, you import the contents of the dsset-child.example.com file into the zonefile for example.com. The easiest way to do this is the following:

cat dsset-child.example.com >> example.com

With the DS record in place, you can now sign the parent zone:

dnssec-signzone -N INCREMENT example.com

When complete, you will see the new keyset and dsset files and the example.com.signed file.  At this point the zones are signed, but BIND needs to be told to load the signed zonefiles instead of the original un-signed ones. Edit named.conf, and add the “.signed” suffix to the zone names. In my environment:

zone "example.com" in {
file "master/example.com";

is replaced with:

zone "example.com" in {
file "master/example.com.signed";

The same applies for child.example.com. Now restart BIND, assuming no errors (they are usually due to syntax), you are now serving DNSSEC signed zones.


DNSSEC validation can be tested by adding “+dnssec” to dig queries. One might think you would be able to try that at this point and get validated data (have the “ad” response flag set), but it won’t work. Dig currently doesn’t perform validation, it just asks for it. It’s the job of a DNSSEC aware resolving server to validate. Fortunately BIND 9.3 and above is capable of that, simply by editing named.conf. If you only wanted to configure a DNSSEC validating resolver without hosting any signed zones, you could pick up here without doing any of the steps above.

If you did follow along, these steps need to be completed on a 2nd BIND installation. Configure this installation to use the first server as a forwarder. This is done because, as mentioned above, BIND will not validate zone data for a zone for which it is authoritative. To set up BIND as a validating recursive server, edit the options section of named.conf to have these entries:

dnssec-enable yes;
dnssec-validation yes;

Note: the dnssec-validation option is only supported on v9.4 or above, on v9.3 the dnssec-enable option covers validation as well.

BIND will now attempt DNSSEC validation, but one more piece is missing. You’ll recall from the previous post that DNSSEC validation relies on climbing a chain-of-trust until it reaches a trusted authority. These trusted authorities are configured by setting a trust-anchor in named.conf to a zone’s Secure Entry Point (SEP), which is the KSK. Ideally you want a trust-anchor configured as high as possible in the chain, which would be the root zone, but this currently is not signed, and neither is .com. In this example, the highest possible point would be example.com.

Obtaining a zone’s KSK (SEP) is fairly easy. Recall that the public key info is added to the zonefile before the signing process (as a DNSKEY record type), so you can simply query for it:

dig <domain.com> DNSKEY

The two public keys created for a zone have a flag field which will be set to either 256 or 257. 256 is the ZSK, 257 is the KSK, which is the SEP, and the one you want to configure as a trust anchor. I’ve found it easiest to pipe that to a file, trim it down to only the SEP record, and import to named.conf.

You’ll then need to edit the named.conf file to format the data correctly, because the way it was imported isn’t complete, but it’s still much easier than manually typing everything. Find where the data was added (at the end of the named.conf file), then remove the necessary text and format it to match this example (pay attention to quotes and semi-colons, and note I’ve truncated the key here):

trusted-keys {
"example.com." 257 3 5 "AwEDSFASDF......";

I should mention that using DNS to obtain a DNSKEY for trust anchor configuration is not considered secure ( you can’t be secure until you have a trust anchor, chicken before the egg kind of situation ). However you can use DNS to obtain the info and verify it via another channel.

Once you’ve got that done, restart BIND. You now have a validating DNSSEC recursive name server.


BIND is now a validating resolver and is configured with a trust anchor, so you should be able to confirm operation by requesting a DNSSEC validated query (against the recursive server) of your zones:

dig +dnssec example.com

dig +dnssec child.example.com

If the data was successfully validated, you will see “ad” listed as one of the flag options in the response, meaning the data returned was Authenticated Data (see previous post for examples). The fact that authorized data is returned for the child domain when you only have a trust anchor configured for the parent confirms the delegation (DS) record was added correctly.

Further testing can be done against other DNSSEC signed zones on the Internet simply by obtaining their SEP key information and adding a trust-anchor.


As mentioned, the goal here was just to show how to configure DNSSEC on BIND. Further research should be done if implementing in production. A few other things are worth mentioning though. It is recommended that the private keys be stored securely offline, or locked down tightly on a primary server that isn’t publicly accessible. Also, record signatures have a default lifetime of 30 days. This can be lengthened, but at some point they will expire. This requires the zone be re-signed before that happens otherwise the zone will no longer validate. A final factor to consider is key rotation, which for security purposes should be done at certain points. RFC 4641 has some suggestions on this subject.


DNSSEC in 6 minutes – Excellent Reference
RFC4641 – DNSSEC Operational Practices
Subscribe to TechScrawl.com


4 Responses

  1. Thanks. This is an excellent summary and quite handy.

  2. Thanks for the shout-out. :) If you have any questions or comments on the “DNSSEC in 6 minutes”, please let me know.

    Also, be aware that the newly available BIND 9.7 (featuring “DNSSEC for humans”) makes DNSSEC much easier to manage (from the authoritative side).

    The first bits of the root being signed have now hit the world (“dig @l.root-servers.net . ns +dnssec”) but are not yet able to be used for validation.

  3. I tried getting this setup, but it wouldn’t work.

    I used dnssec-signzone -N INCREMENT -a -t -g -o example.com example.com.zone and that seemed to work fine, but once I added trusted-keys to my caching resolved, it refused to do anything, insisiting that it was “not insecure resolving”.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: