DNSSEC Automation with Knot - Automated Bootstrapping

This article is part of a series:
  1. Automated Bootstrapping
  2. Automated KSK Rollover

UPDATE: Due to how KSK algorithm rollovers work, cds-cdnskey-publish: double-ds should not be used. The configuration example below has been updated to use cds-cdnskey-publish: always instead.

Knot DNS is an authoritative DNS name server developed by CZ.NIC. One of the features that sets it apart from BIND and other nameserver software is its support for fully automated DNSSEC key management. In this blogpost I'll show how to achieve fully automated DNSSEC bootstrapping, assuming that the parent zone implements trust management via CDS/CDNSKEY records.


Usually, in order to bootstrap a DNSSEC trust relationship, a series of steps is necessary:

  1. A KSK and ZSK or CSK must be created for the child zone (e.g. s3lph.ch.).
  2. The public keys must be published in the child zone as DNSKEY records.
  3. The zone's records must be signed with the ZSK, with the exception of the DNSKEY records, which must be signed by the KSK.
  4. A DS record matching the KSK must be created.
  5. The DS record must be published in the parent zone (e.g. ch.).

Most of these steps can be automated and contained within a single piece of software such as Knot, but the last step usually requires a human to sign into their domain registrar's web management interface and configure the DS record manually.

RFC 8087 describes a mechanism to automate this last step. In order to achieve this, two new DNS RR types were introduced: CDS and CDNSKEY. They serve as a way for the child zone to tell the parent zone "I want the parent zone to serve DS records for these KSKs". Both types serve the same purpose, the only difference is that the CDNSKEY records are copies of the DNSKEY records for which a DS record should be created in the parent zone, whereas the CDS records are already-prepared DS records for the parent zone to copy. This can not only be used for bootstrapping DNSSEC upon introduction, but also for maintaining the chain of trust when rolling over to a new KSK.

The procedure to bootstrap or update a trust relationship using CDS/CDNSKEY records boils down to:

  1. The CDNSKEY and/or CDS records are published in the child zone.
  2. The parent zone scans all its child zones for CDNSKEY/CDS changes on a regular basis (e.g. once a day). Usually this is done by the registry operating the zone.
  3. DS records are computed from the CDNSKEY/CDS records and inserted into the parent zone.

Usually this last step is bound to a set of policies defined by the registry. For example, the CDS policies of SWITCH, the registry for the ch. and li. TLDs, require among other things:

  • The set of CDS records must be valid and consistent across all of the zone's nameservers
  • The new DS records must not break the chain of trust
  • the CDS records are signed with an already trusted KSK

Note: From hereon, every mention of CDS will imply CDS and/or CDNSKEY unless otherwise noted.

DNSSEC Bootstrap Example

Let's look at an example and have DNSSEC automatically bootstrapped for the s3lph.ch. zone. At first, immediately after setting up Knot to enable DNSSEC, keys are generated, the zone is signed and the keys and CDS records are published in the zone:

; KSK and ZSK
s3lph.ch.   300 IN  DNSKEY  257 3 14 zjmE...AnD5 ; KSK ; key id = 46451
s3lph.ch.   300 IN  DNSKEY  256 3 14 fSZj...d+gU ; ZSK ; key id = 19881
; ZSK signature, signed with KSK
s3lph.ch.   300 IN  RRSIG   DNSKEY ... 46451 ...
; CDS referencing the KSK
s3lph.ch.     0 IN  CDS     46451 14 2 C129...DDC0
; CDS signature, signed with KSK
s3lph.ch.     0 IN  RRSIG   CDS ... 46451 ...
; AAAA record, signed with ZSK
s3lph.ch.   300 IN  AAAA    2a01:4f8:1c1c:1ae7::1
s3lph.ch.   300 IN  RRSIG   AAAA ... 19881

However, the ch. zone does not yet know about DNSSEC in the s3lph.ch. zone:

s3lph.ch.   3600    IN  NS  ns1.s3lph.me.
s3lph.ch.   3600    IN  NS  ns2.s3lph.me.

You can also see the chain of trust visualized in Figure 1. The foundation for this image has been created using the the online tool DNSViz resp. it's eponymous backend tool. I've added the CDS node manually afterwards, since DNSViz does not (yet) support CDS.

Visualization of the DNSSEC chain of trust before CDS bootstrapping.
Figure 1: Visualization of the DNSSEC chain of trust before CDS bootstrapping. Note the black arrow between ch. and s3lph.ch. indicating insecure delegation, as well as the NSEC3 record indicating the absence of a DS record.

One day later, we can see that SWITCH has successfully picked up the CDS record:

SWITCH CDS Status Check tool reporting "pending" status after the first successful validation.
Figure 2: SWITCH's CDS Status Check tool reporting "pending" status after the first successful validation.

However, SWITCH requires the CDS RRset to remain unchanged for 3 days when bootstrapping DNSSEC on a zone, so they haven't published the matching DS record yet.

Let's fast-forward to 3 days later: There now is a DS record in the ch. zone:

s3lph.ch.   3600    IN  NS      ns1.s3lph.me.
s3lph.ch.   3600    IN  NS      ns2.s3lph.me.
s3lph.ch.   3600    IN  DS      46451 14 2 C129...DDC0
s3lph.ch.   3600    IN  RRSIG   DS ...
Visualization of the DNSSEC chain of trust after CDS bootstrapping.
Figure 3: Visualization of the DNSSEC chain of trust after CDS bootstrapping, as rendered by DNSViz. Again, the CDS record was added afterwards. Note the arrow between ch. and s3lph.ch. has turned blue, indicating secure delegation, as well as the new DS record in the ch. zone.

And there we have it: The DNSSEC trust relationship between ch. and s3lph.ch. has been established without any manual interaction.

Now let's look into how to set up Knot for this.

Set Up Knot for Fully Automated DNSSEC Key Management

Let's have a look at my /etc/knot/knot.conf. I've boiled it down to the relevant pieces:

  - domain: s3lph.ch.
    # This option tells Knot to enable automatic zone signing ...
    dnssec-signing: on
    # ... and this tells Knot HOW to sign the zone.
    dnssec-policy: dnssec-s3lph.ch.

  # This is the Knot DNSSEC signing policy for s3lph.ch.
  - id: dnssec-s3lph.ch.
    # SWITCH doesn't yet support ed25519/ed448, so let's use some other
    # recommended algorithm, ECDSA using the P-384 curve, plus SHA384.
    algorithm: ecdsap384sha384
    # Automatically create NSEC3PARAMs as well, and respond with NSEC3
    # instead of regular NSEC.
    nsec3: on
    # This is the magic bit to turn on CDS and CDNSKEY record generation.
    # "always" means that a CDS record is always published, not only during KSK rollovers.
    # Before, I had used "double-ds" here, which publishes a CDS RRset for both the
    # old and the new key during rollover, which unfortunately breaks when rolling over to
    # a different KSK algorithm (see update at the top of this page).
    cds-cdnskey-publish: always

And that's already it; those few lines are enough to have Knot automatically sign zones and generate CDS and CDNSKEY records on the fly.

There are other options available for the cds-cdnskey-publish option, you can look up the list in the Knot Configuration Reference.


If your registry supports CDS or CDNSKEY, this is a really simple method to bootstrap DNSSEC without any manual intervention. Even more, this still works if the registrar through which you bought your domain doesn't offer a way to configure DS records.

This procedure can also be used to make KSK rollovers fully automatic, which I'll be covering in the next blogpost.