DNSSEC signing your domain with BIND inline signing

Update Dez 2020: We made an update for users with BIND 9.16.

Update Nov 2017: DNSSEC zone signing as described here is outdated. We strongly recommend against the method described in this blog post. Newer BIND versions or other DNS software have greatly simplified DNSSEC signing.

With BIND 9.9, ISC introduced a new inline signing option for BIND 9. In earlier versions of BIND, you had to use the dnssec-signzone utility to sign your zone. With inline signing, however, BIND refreshes your signatures automatically, while you can still work on the unsigned zone file to make your changes.

This blog post explains how you can set up your zone with BIND inline signing. The zone we are using is called example.com. In addition, we look at how to roll over your keys. In our example, we do a Zone Signing Key (ZSK) rollover. We expect that you are already familiar with ISC BIND and have a basic understanding of DNSSEC. More specifically, you should be able to set up an authoritative-only name server and have read up on DNSSEC and maybe used some of its functions already.


Before we set up inline signing with BIND, let us look at a typical network architecture. We will set up inline signing on a hidden master name server. This server is only reachable from the Internet via one or more publicly reachable secondary name servers. We will only cover the configuration of the hidden master as the secondary name server configuration will not differ for the signed zone (assuming you are using DNSSEC-capable name server software).

Hidden master setup

The default configuration directory of BIND is /etc/bind/. We will create two sub-directories named keys and zones. The keys directory will contain the public/private keys of the zones, the zones directory will contain any locally configured zone.

The configuration file of BIND /etc/bind/named.conf contains the following zone statement for the example.com zone prior to signing it:

zone example.com. {
    type master;
    file "/etc/bind/zones/db.example.com";

The example zone content is taken from a previous blog post about zone time value recommendations. It is important to note here that this example zone has an expiry time of two weeks and a maximum zone TTL of two days.

Answers for the currently served example.com zone should be unsigned. Please verify this on your hidden master. The following command is executed on the hidden master itself, which is why the destination is set to the IPv6 localhost address:

dig @::1 example.com +dnssec

Creating keys

We will create both a Key Signing Key (KSK) and a Zone Signing Key (ZSK). Unless you can easily automate key rollover with your parent zone, we recommend sticking to a split key scheme. This is covered in more detail in the DNSSEC Operational Practice Statement (RFC6781), Section 3.1 “Operational Motivation for Zone Signing Keys and Key Signing Keys”. The keys are created with the following commands:

cd /etc/bind/keys
dnssec-keygen -a RSASHA256 -b 2048 -f KSK example.com
Generating key pair..............................................+++ ..+++
dnssec-keygen -a RSASHA256 -b 1024 example.com
Generating key pair..++++++ ..................................++++++

The first dnssec-keygen command creates the KSK with a key size of 2,048 bits using the RSA-SHA-256 DNSSEC algorithm. The second command creates the ZSK with a key size of 1,024 bits. Resolvers that support newer DNSSEC algorithms such as RSA-SHA-256 or RSA-SHA-512 support NSEC3 as well. If you want to use NSEC3 instead of the default NSEC, you do not need to stick to NSEC3-RSA-SHA1, which has NSEC3 in its name. NSEC3-RSA-SHA1 is identical to RSA-SHA1 and was only introduced to keep backwards compatibility for NSEC3-unaware resolvers. (See RFC5155, Section 2 “Backwards Compatibility”).

We will not cover how to use NSEC3. Instead, we are using the default NSEC. NSEC3 has been implemented to prevent zone walking. However, for most general zones it merely makes it a little more difficult. We would therefore not recommend using NSEC3 unless certain policies state that you have to. ISC BIND has a knowledge base article that discusses inline signing with NSEC3, in case you prefer to use NSEC3 for any reason.

Changing BIND configuration

We will now adapt the BIND configuration file to use inline signing. We start by changing the global options section with some general settings:

options {
    # look for dnssec keys here:
    key-directory "/etc/bind/keys";
    # only sign DNSKEY with KSK
    dnssec-dnskey-kskonly yes;
    # expiration time 21d, refresh period 16d
    sig-validity-interval 21 16;

We specified the keys directory and also told BIND to only sign the DNSKEY RR with the KSK. We also changed the defaults of the sig-validity-interval, although BIND uses good defaults here. The motivation for changing the default sig-validity-interval values is to address some time implications when signing a zone. The first parameter of sig-validity-interval defines how many days into the future automatically generated DNSSEC signatures will expire. The optional second field specifies how long before expiry the signatures will be regenerated. The expiration time is set to signing time plus 21 days. The inception time is unconditionally set to one hour before signing time. The second field tells BIND that signatures are refreshed within a given period of time before expiration. This is called the refresh period, and it is 16 days in our case. Practically, this means that signatures are refreshed after five days (21 – 16). If you first sign your zone, BIND will not distribute the signature expiration time evenly during the refresh period. This would be an advantage for very large zones because then the signer would only need to refresh a few signatures every time it attempted to do a re-sign. However, for most zones this fine control is not needed.

Time in DNSSEC

Time in DNSSEC

  • Signature Validity: This is the fundamental time scale for signatures. It starts at the (absolute) time specified in the signature inception field of the RRSIG RR and ends at the (absolute) time specified in the expiration field of the RRSIG RR.
  • Refresh Period: This is the minimum time period for which each signature is valid at all times. The signer visits the zone content and only refreshes signatures that are within this given period of time before expiration.
  • Re-Sign Check: This is the interval at which BIND inline signing checks whether any signatures need to be regenerated.

To sum it up, BIND will create signatures that are always valid for at least 16 days. This is two days more than the zone’s expiry value of 14 days. The advantage of this is that, if a secondary name server fails to transfer the zone from the hidden master for a longer period of time, we do not run the risk of this name server serving expired signatures. The two-day difference is chosen for safety in case BIND inline signing fails to check its signatures in good time and also because it takes some time from resigning a signature until that signature is transferred to the secondary name server. Of course, two days is a very large buffer, but feel free to lower that to one day if you prefer.

Next we adapt the zone statement. It now looks as follows:

zone example.com {
    type master;
    file "/etc/bind/zones/db.example.com”;
    # publish and activate dnssec keys
    auto-dnssec maintain;
    # use inline signing 
    inline-signing yes;

We tell BIND to reload the configuration, which will sign the zone for the first time (you may want to check your BIND logs afterwards as well):

/usr/sbin/rndc reconfig

If you check your zone with the dig command again, you will see that it is signed:

dig @::1 example.com +dnssec

In addition, the /etc/bind/zones directory now contains a signed version of your zone. Congratulations, you now have signed the example.com zone. To summarise the changes so far, we created two keys, we added some settings to the global options section of the BIND configuration file, and we also adapted the zone statement. Then we told BIND to reload the configuration, which signed the zone. There was no need to modify the unsigned zone at all.

Keep in mind that you still need to increment the zone’s serial number when you make changes to your zone manually. BIND itself will also increment the zone’s serial number when it automatically renews signatures. If you expect more than a few changes for your zone each day, you may want to reconsider the serial number format you are using. The example.com zone is using the YYYYMMDDnn format. This format allows up to 99 changes each day. With inline signing turned on, BIND will also increment the number by one, but it will increment it regardless of the time format. Check out the zone configuration setting serial-update-method and read about how to reset the zones serial number if you feel like switching to a unixtime serial number format.

Once you feel comfortable with your signed zone, you should not forget to add a trust anchor to the parent zone. Most registrars require either the DNSKEY or the DS record of the KSK. You can get the DS record with the following command:

dnssec-dsfromkey Kexample.com.+008+47116.key
example.com. IN DS 47116 8 1 ACA0637A914CAF1AE331CFB8E42FAEC42C64E213
example.com. IN DS 47116 8 2 811F796149050EFBD5175B780BF2325379B6BF2BD3C30E3BB0DB064D2501B899

Recommended monitoring

It is crucial that you keep the system time of the hidden master synchronised to a time server. Apart from running an NTP daemon on your system, it is also important to monitor not only that this daemon is running but also that the system time is still current. Otherwise, if at one point your firewall prohibits your hidden master from contacting your time server, things can quickly go utterly wrong.

Secondly, you should also monitor the lowest expiration time of the signed zones. You want to make sure that every signature is at least valid for the expiry time of the zone. You can either use a tool such as validns or transfer the zone with some scripts and parse the output. Of course, this should never happen as BIND is being told to refresh signatures, but you never know!

Thirdly, we suggest that you monitor whether all name servers serve the same zone by checking if the serial number is equal on all servers. This is to notify you if one of the secondary name servers has failed to update the zone. Finally, it is also good to validate the chain of trust to your signed zone. BIND 9.10.0 contains a new tool called delv, which provides a very readable output that could be used for this purpose.

Key rollover is good practice

There is no requirement to roll over (i.e. change) either the KSK or the ZSK, but it is good practice to roll over either of these keys. You can easily roll over the ZSK yourself without any interactions with the parent zone. We therefore advise rolling over the ZSK every few months. The KSK can be rolled over as needed. Some people roll over the KSK every year for operational practice or according to their policy (See also RFC6841, A Framework for DNSSEC Policies and DNSSEC Practice Statements). In our view, a KSK rollover every one to three years is reasonable. The DNSSEC Operational Practice Statement (RFC6781) lists some more considerations on the key effectivity period.

The most common method for a ZSK key rollover is pre-publication. In this approach, you pre-publish the new DNSKEY in advance until you can guarantee that all resolvers hold both the old and the new DNSKEY in their cache. This is typically after the DNSKEY RR TTL, in our case, after one day. At that time, it is safe to start signing with the new ZSK. Some signing applications do a complete re-sign of the whole zone with the new ZSK at that point. However, this is not how BIND inline signing works. BIND will gradually refresh signatures according to the refresh period, regardless of whether or not we do a key rollover. It can thus take up to five days in our case until all signatures in the zone are refreshed with the new ZSK. After that, you keep the old ZSK in the zone for the maximum TTL of any record in the zone. This is to make sure that, if a resolver holds a signature from the old ZSK in its cache, it can still validate it. In our case, this period is two days. Only then should you remove the old ZSK.

You now have two options for this kind of ZSK rollover. The common way is to monitor the propagation of your zone after each change and to only continue if all name servers are up to date. The reason is that you do not want, for example, to remove the old ZSK if one of the secondary name servers is no longer updating your zone. In such a situation, this secondary name server might still provide signatures of the old ZSK for as long as the zone’s expiry time. If you were to remove the old ZSK, a resolver which got the ZSK from an up-to-date secondary name server would only have the new ZSK in its cache but may have signatures from the out-of-date secondary generated by the old ZSK. However, in order to keep the ZSK rollover schedule simple, we can also increase the pre-publication and post-publication time to at least the zone’s expiry time. That way, should one secondary name server be out of sync, the zone expires before the ZSK rollover in progress can cause any problems. Below are the timing details of the ZSK rollover schedule with the increased pre-publication and post-publication time:

Minimal ZSK rollover time:

  • pre-publication of new ZSK : DNSKEY RR TTL of 1 day + zone transfer time of < 1 day
  • post-publication of old ZSK: (expiration period of 21 days – refresh period of 16 days) + maximum zone TTL of 2 days + zone transfer time of < 1 day

Increased ZSK rollover time:

  • pre-publication of new ZSK : SOA expiry time of 14 days + zone transfer time of < 1 day
  • post-publication of old ZSK: (expiration period of 21 days – refresh period of 16 days) + SOA expiry time of 14 days + zone transfer time of < 1 day

Now that we have discussed how to roll over the ZSK, we can execute these commands. The following method is based on the conservative approach:

1. Set the inactivation and deletion date of the current (old) ZSK
-I inactivation interval is set to 15 days + 1 hour (pre-publication)
-D deletion interval is set to 35 days (pre-publication + post-publication)

cd /etc/bind/keys
dnssec-settime -I +1299600 -D +3024000 Kexample.com.+008+51498.key

2. Generate a successor ZSK
-i pre-publication interval is set to 15 days

dnssec-keygen -S Kexample.com.+008+51498.key -i 1296000
Generating key pair........++++++ ..........................................++++++

3. Load the new keys

/usr/sbin/rndc loadkeys example.com

The ZSK rollover starts in one hour with the pre-publication of the new ZSK, which is why we added “1 hour” to the inactivation date of the old ZSK. This allows you to reverse the change again if you need to cancel the ZSK rollover for any reason. After 35 days (pre-publication and post-publication period), the ZSK rollover is finished. You can use public tools such as DNSViz or the command line tool dig to verify each step manually if needed. After the ZSK rollover is finished, you can archive and eventually delete the old ZSK. If you look back at how we executed the ZSK rollover, you see that it only required three commands. The only variable input to these commands is the current (old) ZSK. That said, it is very simple to automate a ZSK rollover.

%d bloggers like this: