DNSSEC signing with an offline KSK

Prev Next

This article describes how to configure and operate BIND 9 with an offline KSK.
It is assumed that the reader has a general understanding of DNSSEC.

Supported BIND 9 versions

The Offline KSK feature was introduced in BIND 9.20.2. Support for KSK rollover in this mode was added in 9.20.4

When signing your zone with DNSSEC, you have the option to use a single key that signs the complete zone (CSK), or to use two keys and split the roles of signing key material and zone data (the so-called KSK/ZSK split). In the latter case, the KSK signs the data that interacts with the parent, such as the DNSKEY, CDS and CDNSKEY RRsets. Using an offline KSK allows for stricter access control and offers better protection against key compromise, without sacrificing too much operational flexibility. Offline KSK is also a good practice when your zone is signed by multiple providers (see model 1 in RFC 8901 Multi-Signer DNSSEC Models).

The implementation in BIND 9 is loosely based on DNSSEC Key Management Implementation for the Root Zone. Here is some useful terminology to know before continuing with this article:

Key Signing Request (KSR): A file containing one or more ZSKs that need to be signed with the KSK, divided into bundles, where each bundle contains the current published ZSKs. Having multiple bundles means that planned ZSK rollovers are supported.

Signed Key Response (SKR): A file containing multiple signed DNSKEY RRsets (possibly CDS and CDNSKEY RRsets, too) divided into bundles, where each bundle introduces a new signature generated by the set of KSKs. Similar to ZSKs within the KSR, a KSK rollover may be in progress at any point when generating the SKR: each bundle has RRsets signed with the signature of the KSK that is active at the given time.

To enable the offline KSK feature in BIND 9 you need to have a dnssec-policy configured with offline-ksk set to yes, as shown in the example below.

dnssec-policy "offlineksk" {
    offline-ksk yes;
    keys {
        ksk lifetime P5Y algorithm 13;
        zsk lifetime P6M algorithm 13;
    };
};

zone "offlineksk.example" {
    type primary;
    file "offlineksk.example.db";
    dnssec-policy offlineksk;
};

In order to sign your zone with an offline KSK there are four steps that you need to follow:

  1. Pregenerate ZSKs
  2. Request signing of the public keys
  3. Wait for a Signed Key Response (done by the KSK operator)
  4. Load the SKR into the name server

ZSK Creation

Before pregenerating the ZSKs, you need to decide for how long you want to have signed DNSKEY (and corresponding) RRsets. This depends on how often the key signing ceremony takes place. For example, if you issue a KSR every six months you may want to generate keys for a bit longer than that, such as seven months. Given the example above, we can use dnssec-ksr with the keygen command as follows:

$ dnssec-ksr -i now -e +7mo -k offlineksk -l named.conf keygen offlineksk.example

This will create the right number of ZSKs, which in this case is two, because the request is for seven months and the key lifetime is configured to be six months.

Multiple runs of dnssec-ksr keygen

It may be useful to know that if you run dnssec-ksr keygen multiple times in succession, it will not create more keys. This means you can also run the tool with an interval that starts in the past, and then it will only create new keys for the part of the interval for which it has no keys yet.

Creating the KSR

Now that we have some keys on disk, we can create the Key Signing Request (KSR). We can use dnssec-ksr again, but now we use the request command:

$ dnssec-ksr -i now -e +7mo -k offlineksk -l named.conf request offlineksk.example > offlineksk.example.ksr

The KSR is stored in offlineksk.example.ksr. If you inspect the file, you will see some DNSKEY records:

;; KeySigningRequest 1.0 20251230103230 (Tue Dec 30 11:32:30 2025)
offlineksk.example.     3600    IN      DNSKEY  256 3 13 lqRPZ0eV...
;; KeySigningRequest 1.0 20260704082730 (Sat Jul  4 10:27:30 2026)
offlineksk.example.     3600    IN      DNSKEY  256 3 13 lqRPZ0eV...
offlineksk.example.     3600    IN      DNSKEY  256 3 13 lAU8lGME....
;; KeySigningRequest 1.0 20260714113730 (Tue Jul 14 13:37:30 2026)
offlineksk.example.     3600    IN      DNSKEY  256 3 13 lAU8lGME....
;; KeySigningRequest 1.0 generated at Tue Dec 30 11:32:30 2025 by 9.21.17

This file is to be sent to the party that is responsible for KSK signing.

Creating the SKR

Typically, another organization creates the Signed Key Response (SKR), but we will discuss it here a bit, as well.

KSK Creation

You can also use the dnssec-ksr keygen command to generate KSKs.
With -o set, the tool will create KSKs instead of ZSKs.

Once you have a set of KSKs, you can now use dnssec-ksr to sign the KSR:

$ dnssec-ksr -i now -e +7mo -k offlineksk -l named.conf -f offlineksk.example.ksr sign offlineksk.example > offlineksk.example.skr

Here, we use the same DNSSEC policy, but in reality, just the parameters need to match. The SKR is stored in offlineksk.example.ksr, and looking at the contents it, is a much larger file:

;; SignedKeyResponse 1.0 20251230103230
offlineksk.example. 3600    IN      DNSKEY 257 3 13 DXnO/2Vd....
offlineksk.example. 3600    IN      DNSKEY 256 3 13 lqRPZ0eV...
offlineksk.example. 3600    IN      RRSIG DNSKEY 13 2 3600 ....
;; SignedKeyResponse 1.0 20251231083230
offlineksk.example. 3600    IN      DNSKEY 257 3 13 DXnO/2Vd...
offlineksk.example. 3600    IN      DNSKEY 256 3 13 lqRPZ0eV....
offlineksk.example. 3600    IN      RRSIG DNSKEY 13 2 3600 ....
offlineksk.example. 3600    IN      CDNSKEY 257 3 13 DXnO/2Vd....
offlineksk.example. 3600    IN      RRSIG CDNSKEY 13 2 3600 ....
offlineksk.example. 3600    IN      CDS 9346 13 2 86DEA628....
offlineksk.example. 3600    IN      RRSIG CDS 13 2 3600 ...
...

The above output is abbreviated for better readability. This contains all signed DNSKEY, CDS, and CDNSKEY RRsets that we need from now until seven months in the future. Each bundle has a start and end time; the end time is determined by the start time of the next bundle.

This response needs to be returned to the zone operator, the sender of the KSR.

Load the SKR into BIND 9

Now that we have an SKR, we need to import the file into BIND 9. This can be done using rndc wiith the skr command:

$ rndc skr -import offlineksk.example.ksr offlineksk.example