Blog>>Networks>>Practical Guide to DNSSEC Key Management on BIND

Practical Guide to DNSSEC Key Management on BIND

While understanding the theory behind DNSSEC keys and rollover strategies is essential, putting this knowledge into practice is equally important. This article focuses on how DNSSEC key management is implemented in BIND and shows step-by-step examples of rollover events on a real DNS server. Building on the concepts introduced in our previous article, Understanding DNSSEC Key Types, Rollover, and Chain of Trust, this article provides a hands-on look at DNSSEC policies, key lifecycles, and command-line tools used to maintain a secure and reliable DNSSEC environment.

The following article is the 4th and final part of a longer series revolving around DNSSEC. If you are interested in learning more about DNS and DNSSEC basics, please visit the first article in the series – “Introduction to DNSSEC” (https://codilime.com/blog/introduction-to-dnssec/). If you want to get more familiar with DNSSEC configuration on BIND, you can check out our dedicated article covering this topic – “Practical implementation of DNSSEC” (https://codilime.com/blog/practical-implementation-dnssec/).

DNSSEC key management on BIND

In the previous article (https://codilime.com/blog/practical-implementation-dnssec/#dnssec-configuration), we mentioned different ways of managing DNSSEC keys on BIND. We also showed an example of configuring a BIND DNS server using the latest available method - DNSSEC policy (also known as Key and Signing Policy - KASP). In this section, we will take a deeper dive into topics related to DNSSEC key management on BIND with KASP, with a special focus on rollovers. If you look for details about other methods, please check out the following article (https://www.sidn.nl/en/modern-internet-standards/dnssec-signatures-in-bind-named      link-icon).

By default, BIND, with a configured DNSSEC policy, uses the Pre-Publication strategy for the ZSK key rollover and Double-KSK for KSK. CSK key rollover is a combination of both methods. If key lifetimes are defined in the DNSSEC policy, then the rollover is performed automatically. Otherwise, a DNS administrator must trigger the process manually.

Key lifecycle

The figure below shows a typical lifecycle of a ZSK, KSK, or CSK key maintained under a DNSSEC policy:

Fig.1: DNSSEC keys lifecycle
DNSSEC keys lifecycle

Each key moves through different states during this process. Most relevant states (also shown in the figure above) are:

  • Published – Newly created public key appears in the DNSKEY RRset along with the currently used key. Note that only one key is Active at a time.

    • In this state, the newly created private ZSK key is not used for signing any resource records within a zone (creating RRSIG records).
    • New KSK and CSK private keys are immediately used to sign the DNSKEY RRset, while the old signatures remain unchanged.
  • Active – The key is actively used for signing and validation.

    • The private ZSK key is now being used to sign regular RRsets.
    • In the case of a KSK, the active state means that the public key is known to all resolvers, its DS record is installed at the parent domain, and therefore the key can be used to validate the DNSKEY RRset.
    • The Active state of a CSK key is a combination of both conditions.
  • Retired – The key is not used for signing any new resource records, but it must still be kept in the zone until all resource records are signed by the new key and all resolvers update their caches. Note that the old key becomes Retired at the same time that the successor changes its state to Active.

    • The public ZSK key is present in the DNSKEY RRset; however, the private counterpart is not used to refresh any signatures. The process of re-signing resource records using the new key happens gradually as the old signatures expire. The time when the old key is still present in the zone must be strictly related to the validity period of RRSIG signatures. If the old key is removed from the zone before all records get their signatures refreshed using the new key, validation problems may occur for these records.
    • In the case of a KSK, the old public key is still kept in the DNSKEY RRset to allow proper validation by resolvers with outdated cache information, while the successor key and its respective DS record are used for validation by resolvers that have already updated their cache.
    • The Retired state of a CSK key is a combination of ZSK and KSK conditions.
  • Dead – The key is still present in the DNSKEY RRset, but all resource records are already signed by the new key. The key in that state can be safely removed.

  • Removed – The key is removed from the DNSKEY RRset.

The full list can be found in RFC7853 (https://datatracker.ietf.org/doc/html/rfc7583      link-icon).

Changes in states occur at specific events (Publish, Activate, Inactive, Delete), marked with grey arrows in the figure above.

For each key, we can define three intervals:

  • Publication Interval – The time needed to move from the Published to Active state. This interval must be long enough to ensure that all cached versions of the zone’s DNSKEY resource record include the new public key, and in the case of a KSK/CSK key, its DS record is installed at the parent zone.
  • Key Lifetime – The time when a key is in the Active state, signs resource records, and can be used in the validation process.
  • Retire Interval – The time needed to move from the Retired to Dead state.

Key files

Time information about events and state changes is stored together with respective keys in so-called K* files (since they all start with the capital letter K). There are three files for each key pair. If the zone name is ns-testing.com, the key id is 54249, and the cryptographic algorithm is ECDSAP256SHA256 (13), the file names would be as follows:

  • Kns-testing.com.+013+54249.key – A file containing the public key. Specific event times are written in the comment section:
; This is a key-signing key, keyid 54249, for ns-testing.com.
; Created: 20240621113755 (Fri Jun 21 11:37:55 2024)
; Publish: 20240621113755 (Fri Jun 21 11:37:55 2024)
; Activate: 20240621113755 (Fri Jun 21 11:37:55 2024)
; Inactive: 20250621113755 (Sat Jun 21 11:37:55 2025)
; Delete: 20250625114755 (Wed Jun 25 11:47:55 2025)
; SyncPublish: 20240623143755 (Sun Jun 23 14:37:55 2024)
ns-testing.com. 600 IN DNSKEY 257 3 13 xStQGvplWIM7roZyXLyKfkMWOSgVs5qcbwCoP0B0tlLWdG+/pai0CPNu 6Bs4UJaJtA1Q+YEpglSo/txjOGtzHg==

The SyncPublish attribute shows the date of CDS records publication.

  • Kns-testing.com.+013+54249.private – A file containing the private key. Event times are included as metadata. The DSPublish attribute indicates the date of DS records publication in the parent zone.
Private-key-format: v1.3
Algorithm: 13 (ECDSAP256SHA256)
PrivateKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Created: 20240621113755
Publish: 20240621113755
Activate: 20240621113755
Inactive: 20250621113755
Delete: 20250625114755
DSPublish: 20240621174709
SyncPublish: 20240623143755
  • Kns-testing.com.+013+54249.state – A state file maintained by BIND. Key states are used instead of events to describe timing information. Additionally, we have attributes indicating changes of specific records associated with the key and their current states.
; This is the state of key 54249, for ns-testing.com.
Algorithm: 13
Length: 256
Lifetime: 31536000
KSK: yes
ZSK: no
Generated: 20240621113755 (Fri Jun 21 11:37:55 2024)
Published: 20240621113755 (Fri Jun 21 11:37:55 2024)
Active: 20240621113755 (Fri Jun 21 11:37:55 2024)
Retired: 20250621113755 (Sat Jun 21 11:37:55 2025)
Removed: 20250625114755 (Wed Jun 25 11:47:55 2025)
DSPublish: 20240621174709 (Fri Jun 21 17:47:09 2024)
PublishCDS: 20240623143755 (Sun Jun 23 14:37:55 2024)
DNSKEYChange: 20240623134755 (Sun Jun 23 13:47:55 2024)
KRRSIGChange: 20240623134755 (Sun Jun 23 13:47:55 2024)
DSChange: 20240623143755 (Sun Jun 23 14:37:55 2024)
DNSKEYState: omnipresent
KRRSIGState: omnipresent
DSState: omnipresent
GoalState: omnipresent

The table below lists attributes used to describe DNS records within a state file:

AttributeDescription
DSPublishDS record publication date
PublishCDSCDS record publication date
DNSKEYChangeDate of a DNSKEY RRset change
KRRSIGChangeDate of a KSK RRSIG record change
ZRRSIGChangeDate of a ZSK RRSIG record change
DSChangeDate of a DS record change
DNSKEYStateState of a DNSKEY RRset
KRRSIGStateState of a KSK RRSIG record
ZRRSIGStateState of ZSK RRSIG records
DSStateState of a DS record
GoalStateExpected final state

Table 1: Attributes describing DNS records associated with a specific DNSSEC key.

A state file contains only attributes relevant to a specific key type (KSK, ZSK). A file associated with the CSK key has both ZSK and KSK attributes since that key combines the roles of both key types.

It is possible to manually control specific timers using the dnssec-settime tool; however, this is not recommended when a DNSSEC policy is in place. The tool reads DNSSEC private key metadata and sets specific timers based on provided options. You can also use this command to display timing information in a more human-readable format:

$ sudo dnssec-settime -p all /var/cache/bind/Kns-testing.com.+013+54249
Created: Fri Jun 21 11:37:55 2024
Publish: Fri Jun 21 11:37:55 2024
Activate: Fri Jun 21 11:37:55 2024
Revoke: UNSET
Inactive: Sat Jun 21 11:37:55 2025
Delete: Wed Jun 25 11:47:55 2025
SYNC Publish: Sun Jun 23 14:37:55 2024
SYNC Delete: UNSET
DS Publish: Fri Jun 21 17:47:09 2024
DS Delete: UNSET

More information about available options can be found here (https://bind9.readthedocs.io/en/v9.18.0/manpages.html#dnssec-settime-set-the-key-timing-metadata-for-a-dnssec-key      link-icon).

DNSSEC resource record states

Besides assigning and monitoring states of DNSSEC keys, as defined in RFC7583 (https://datatracker.ietf.org/doc/html/rfc7583      link-icon), BIND also tracks the states of the resource records associated with those keys: DS, DNSKEY, RRSIG used to sign DNSKEY RRsets, and RRSIGs used to sign regular records like A or NS. These states reflect the visibility of specific records to the outside world and, therefore, give us a better view of the rollover process from the DNSSEC validity perspective. BIND stores DNSSEC record states in *.state files (see Table 1 for details).

The concept of DNSSEC record states and terms used in BIND configuration have been taken directly from the paper “Flexible and Robust Key Rollover in DNSSEC” (https://nlnetlabs.nl/downloads/publications/satin2012-Schaeffer.pdf      link-icon). Some useful information about implementing this idea can also be found in the following article (https://kb.isc.org/docs/dnssec-key-states      link-icon).

The paper defines four states of a DNSSEC record:

  • Hidden – A record associated with a specific key is not present in the authoritative zone and in any resolver’s cache.
  • Rumoured –A record has been published, but it is not yet known to all resolvers.
  • Omnipresent – A record is used by all resolvers.
  • Unretentive – A record has been removed from the authoritative server, but some resolvers still use it and will continue to do so until their cache entries expire.

The following figure illustrates how specific DNSSEC records can change their states over time:

Fig.2: States of DNS records associated with a specific DNSSEC key.
States of DNS records associated with a specific DNSSEC key

Every record begins and ends its life in the Hidden state. Then, after being published, it moves to the Rumoured state, where some resolvers may already use it, but for some, it is still unknown, depending on the state of their caches. When all resolvers finally update their caches, the record is now considered Omnipresent. When the record is removed from the authoritative zone, it becomes Unretentive. In this state, some resolvers may still have it in their caches. Eventually, the record goes back to the Hidden state.

The graph in Figure 2 also shows possible direct transitions between the Rumoured and the Unretentive states. These transitions don’t happen in a normal rollover process. They are reserved for some special cases, like ending a rollover prematurely, undoing a rollover, or doing multiple rollovers in parallel.

BIND also implements algorithms and rules defined in the paper to ensure DNSSEC validity at any time (including key rollovers). Here is a brief summary of those rules for the rollover methods used by BIND:

  • Rule #1 – At all times, there must be a DS record published for a zone (in either Rumoured or Omnipresent state). This includes both a stable condition (no rollover in progress) and any moment during a rollover. If this is not met, the zone can’t be considered as trusted.
  • Rule #2 – Applies to DNSKEY resource records. During a stable condition, the DNSKEY resource record, its signature, and associated DS record must be in the Omnipresent state. During a transition from the old key to the new one, when the new key becomes Active, the DNSKEY resource record and its signature also must stay in the Omnipresent state. However, in case of KSK/CSK keys being replaced using the Double-KSK method, the DS record associated with the new key should be in the Roumoured state, while the DS record derived from the old key should be in the Unretentive state.
  • Rule #3 – Very similar to rule #2, but this time applies to RRSIG signatures used to sign regular resource records. During a stable condition, zone RRSIG signatures and the DNSKEY record associated with the key used to create these signatures should be in the Omnipresent state. During a transition from one key to another (Pre-Publication method), RRSIG records associated with the old key should be in the Unretentive state, while RRSIG records created using the new key should be Rumoured. The respective DNSKEY resource record should be Omnipresent at that time.

The following figures illustrate changes in DNSSEC record states during a typical KSK and ZSK rollover on BIND. In the case of a CSK key, that would be simply a conjunction of KSK and ZSK scenarios.

Fig.3: Changes in DNSSEC records states during a KSK rollover (Double-KSK method).
Changes in DNSSEC records states during a KSK rollover (Double-KSK method)
Fig.4: Changes in DNSSEC records states during a ZSK rollover (Pre-Publication method).
Changes in DNSSEC records states during a ZSK rollover (Pre-Publication method).

Key and Signing Policy (KASP)

Timing for each DNSSEC key, including state changes of associated DNSSEC records, is controlled by the DNSSEC policy. Let’s recall the policy that we used in the previous article (https://codilime.com/blog/practical-implementation-dnssec/) for our test domain ns-testing.com:

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

In this example, the KSK key lifetime is set to 365 days, and the ZSK key lifetime is 60 days. The Publication Interval is calculated in the following way:

Publication Interval = dnskey-ttl + publish-safety + zone-propagation-delay

The Retire Interval, on the other hand, is defined as the sum of the following parameters:

ZSK Retire Interval = max-zone-ttl + retire-safety + zone-propagation-delay

KSK/CSK Retire Interval = parent-ds-ttl + retire-safety + parent-propagation-delay

Where:

  • dnskey-ttl - TTL (Time To Live) of the DNSKEY records (in seconds).
  • max-zone-ttl - Specifies the maximum permissible TTL (in seconds) for a zone that uses the policy.
  • parent-ds-ttl - TTL of the DS record defined within the parent zone.
  • parent-propagation-delay - Expected propagation delay from the time when the parent zone is updated with a new DS record to the time when the new version of the record is served by all of the zone’s name servers.
  • publish-safety – Additional, arbitrarily defined time between publishing keys and making them active. This is an extra margin to cover any unforeseen events.
  • retire-safety – Additional, arbitrarily defined amount of time a key remains published after it’s no longer active, to cover any unforeseen events.
  • zone-propagation-delay - Expected delay from the time when a zone is updated to the time when the new version of the zone is propagated to all secondary servers.

Description of all remaining attributes can be found in the previous article (https://codilime.com/blog/practical-implementation-dnssec/#dnssec-on-authoritative-servers), in Table 2.

It is important to note that the Lifetime of a key should be longer than the Publication Interval and the Retire Interval. A too-short Lifetime is treated by BIND as an error. It is also worth mentioning that BIND may alter the Retire Interval derived from the DNSSEC policy if the default value doesn’t guarantee a flawless rollover (e.g. in case of ZSK, the Retire Interval is shorter than signatures validity period).

Keys status verification

In order to verify the current status of DNSSEC keys, you can read the K* files directly. However, a quicker and much easier way is to use the following command:

$ rndc dnssec -status <zone_name>

It is available since BIND 9.16.5 and provides the following information:

  • name of the current KASP policy,
  • all DNSSEC keys, either used or unused,
  • key statuses (published, currently used for signing),
  • statuses of associated DNSSEC records,
  • information about scheduled rollovers and their states.

Here is an example output for the ns-testing.com zone configured in the previous article:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom
current time:  Sun Dec 15 18:09:04 2024

key: 64664 (ECDSAP256SHA256), ZSK
  published:      yes - since Thu Oct 17 09:27:55 2024
  zone signing:   yes - since Sat Oct 19 11:37:55 2024

  Next rollover scheduled on Mon Dec 16 09:27:55 2024
  - goal:           omnipresent
  - dnskey:         omnipresent
  - zone rrsig:     omnipresent

key: 30329 (ECDSAP256SHA256), ZSK
  published:      no
  zone signing:   no

  Key has been removed from the zone
  - goal:           hidden
  - dnskey:         hidden
  - zone rrsig:     hidden

key: 54249 (ECDSAP256SHA256), KSK
  published:      yes - since Fri Jun 21 11:37:55 2024
  key signing:    yes - since Fri Jun 21 11:37:55 2024

  Next rollover scheduled on Thu Jun 19 09:27:55 2025
  - goal:           omnipresent
  - dnskey:         omnipresent
  - ds:             omnipresent
  - key rrsig:      omnipresent

The output above shows information about three keys with the following IDs:

  • 64664 – Currently used ZSK key (Omnipresent status), with the information about its publication, activation (beginning of zone signing), and next rollover date.
  • 30329 – Previous, already removed ZSK key (Hidden status)
  • 54249 – Currently used KSK key (Omnipresent status), also with respective information about publication, activation, and next rollover dates.

Rollovers

In the case of a ZSK key, the rollover doesn’t require any interaction with the DNS administrator. The KSK or CSK rollover, on the other hand, requires submitting new DS records to the parent domain. If the parent domain doesn’t support any automatic interaction with the child domain, by means of CDS/CDNSKEY records, this has to be done manually by the administrator of the child domain at a specific time, dependent on the chosen rollover method.

Another important thing to remember during a KSK or CSK rollover is informing the BIND server about every manual change in DS records being installed at the parent domain. BIND won’t remove the old key from the DNSKEY RRset unless it knows that the respective DS record has been withdrawn from the parent domain. On the other hand, the DS record status of a newly introduced KSK/CSK will be stuck in the Rumoured state if BIND is not informed that this record has actually been published at the parent domain.

DS records status signaling can be done manually using the following commands (available since BIND 9.16.7):

rndc dnssec -checkds -key <new_key_id> [-when YYYYMMDDHHMMSS] published <zone_name>
rndc dnssec -checkds -key <old_key_id> [-when YYYYMMDDHHMMSS] withdrawn <zone_name>

The first command informs BIND that the DS record of a specific KSK/CSK key has been added to the parent domain. The second command indicates that the DS record of a specific KSK/CSK key has been removed from the parent domain.

In both cases, by default, the notification is sent to BIND immediately. You can optionally specify the time when the notification is to be sent (-when option).

When using the Double-KSK rollover method, both commands should be issued at the same time, right after the DS record has physically been modified in the parent zone (Figure 11). More formally, the publication of the new DS record should be done when the successor KSK key becomes Active, associated DNSKEY and RRSIG records move to the Omnipresent state, and the DS record itself becomes Rumoured, according to the rndc tool (that is, when the Publish Interval elapses). The withdrawal of the old DS record should be performed as soon as it changes its state to Unretentive (or when the old KSK key enters the Retired state). Note that after issuing both commands, BIND won't immediately change the state of the new and the old DS record to the Omnipresent and Hidden state, respectively. Instead, it will wait for the whole Retire Interval.

Since version 9.16.19, we can also configure BIND to automatically monitor changes in DS records for specific zones. This can be done by adding “parental agents” – trusted DNS servers used to provide responses for DS queries:

zone "ns-testing.com" {
        type primary;
        file "/var/lib/bind/db.ns-testing.com";
        allow-transfer { 98.71.216.161; };
        dnssec-policy custom;
        inline-signing yes;
        parental-agents { 192.168.38.128; };
};

BIND 9.19.12 and higher can automatically detect and set authoritative name servers of a parent zone as parental agents. This behavior can be controlled by using additional option checkds. For details, see release notes (https://bind9.readthedocs.io/en/v9.19.24/notes.html#notes-for-bind-9-19-12)      link-icon and documentation (https://bind9.readthedocs.io/en/stable/reference.html#namedconf-statement-checkds      link-icon).

The start of particular rollover events is derived from the DNSSEC policy based on the key Lifetime and the Publication Interval. However, at any time, it is possible to trigger a rollover by hand. The lifetime of the current DNSSEC key is shortened; however, the Publication Interval of the new key and the Retire Interval of the old key are retained (Figure 13). Also the new key has the Lifetime set according to the policy.

Fig.5: Manual rollover of a DNSSEC key.
Manual rollover of a DNSSEC key.

To manually trigger a rollover, you can use the following command (available since BIND 9.16.8):

rndc dnssec -rollover -key <key_id> [-when YYYYMMDDHHMMSS] <zone_name>

If you don’t specify the exact time, the rollover will start immediately.

Note that starting a new rollover when the old one hasn’t finished yet may cause unexpected results. For example, on BIND 9.18.28, if you do it for a KSK or CSK key with its DS record in the Hidden state, BIND will immediately replace the key without retaining any Publication or Retire Interval.

DNSSEC key rollover examples

In this section, we are going to show some real-life examples of DNSSEC key rollover events. They are based on a setup that has been presented in the previous article (https://codilime.com/blog/practical-implementation-dnssec/). Here are some key features of the environment used in the examples:

  • BIND 9.18.28,

  • Test domain: ns-testing.com,

  • One primary DNS server and one secondary,

  • Separate ZSK and KSK keys,

  • Custom KASP policy with 365-day KSK lifetime, 60-day ZSK lifetime, and the following timers set within the dnssec-policy statement:

    • max-zone-ttl - 1h
    • dnskey-ttl – 600s
    • max-zone-ttl – 1h
    • parent-ds-ttl – 600s
    • parent-propagation-delay – 2d
    • publish-safety – 2d
    • retire-safety – 2d
    • signatures-refresh - 5d
    • signatures-validity - 15d
    • signatures-validity-dnskey - 15d
    • zone-propagation-delay – 2h
  • No parental agents in the zone configuration,

  • No support for CDS/CDNSKEY records at the parent zone.

ZSK rollover

Initial DNSSEC status of the ns-testing.com zone can be checked using the rndc tool:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom
current time:  Sun Dec 15 18:09:04 2024

key: 64664 (ECDSAP256SHA256), ZSK
  published:      yes - since Thu Oct 17 09:27:55 2024
  zone signing:   yes - since Sat Oct 19 11:37:55 2024

  Next rollover scheduled on Mon Dec 16 09:27:55 2024
  - goal:           omnipresent
  - dnskey:         omnipresent
  - zone rrsig:     omnipresent

(truncated output)

Both the ID of the ZSK key that is going to be replaced, and the date of the rollover are marked in red in the output above. Figure 6 shows a graphical representation of the zone before the ZSK rollover (created using the DNSViz tool https://dnsviz.net/d/ns-testing.com/dnssec/      link-icon).

Fig.6: DNSViz graph for the ns-testing.com zone before the ZSK rollover.
DNSViz graph for the ns-testing.com zone before the ZSK rollover.

At the beginning of the next rollover, a new ZSK private/public key pair is generated by BIND (ID 36436), and the public part is added to the DNSKEY RRset:

$ dig @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53395
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;ns-testing.com.                IN DNSKEY

;; ANSWER SECTION:
ns-testing.com.         600 IN DNSKEY 256 3 13 (
                                vbK10NMUWFVQuR+9otsNwiTL4LuzxRoxEWRqySb+2mhs
                                2yDyAoI1QpmiE0Ntxbs55KTx7UMekX6qQ0FIgqTEXA==
                                ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 36436
ns-testing.com.         600 IN DNSKEY 256 3 13 (
                                3fpXX5G0NaucQoYWgFQyT96UXMfxL6aiYpbevPAnUTjB
                                C8DajuvNcc8T2Rreaki4ajq4pAeRuXVEXbzaryKPHA==
                                ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 64664
ns-testing.com.         600 IN DNSKEY 257 3 13 (
                                xStQGvplWIM7roZyXLyKfkMWOSgVs5qcbwCoP0B0tlLW
                                dG+/pai0CPNu6Bs4UJaJtA1Q+YEpglSo/txjOGtzHg==
                                ) ; KSK; alg = ECDSAP256SHA256 ; key id = 54249
ns-testing.com.         600 IN RRSIG DNSKEY 13 2 600 (
                                20241231092755 20241216082755 54249 ns-testing.com.
                                DHuRdzRAksmYPd9eU5rbSbvhbU0JerYIlBOm6qJ+1Y1q
                                wICkql5dYcuaIKaP0lWHI9qMIWemz1JF3saafa1CDA== )

;; Query time: 66 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Mon Dec 16 13:01:59 CET 2024
;; MSG SIZE  rcvd: 393

Note that the DNSKEY RRset already contains records with two other public keys: current KSK (ID 54249) and current ZSK (ID 64664).

At this point, the new key doesn’t sign any records yet (zone RRSIG records in Hidden state), except the SOA record - Start Of Authority (also signed by the old key). The new key will start to be used at the same time as the old key enters the Retired state:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom
current time:  Mon Dec 16 09:43:12 2024

key: 36436 (ECDSAP256SHA256), ZSK
  published:      yes - since Mon Dec 16 09:27:55 2024
  zone signing:   no  - scheduled Wed Dec 18 11:37:55 2024

  Next rollover scheduled on Fri Feb 14 09:27:55 2025
  - goal:           omnipresent
  - dnskey:         rumoured
  - zone rrsig:     hidden

key: 64664 (ECDSAP256SHA256), ZSK
  published:      yes - since Thu Oct 17 09:27:55 2024
  zone signing:   yes - since Sat Oct 19 11:37:55 2024

  Key will retire on Wed Dec 18 11:37:55 2024
  - goal:           hidden
  - dnskey:         omnipresent
  - zone rrsig:     omnipresent

(output truncated)
Fig.7: DNSViz graph for the ns-testing.com zone during the Publish Interval of the new ZSK.
DNSViz graph for the ns-testing.com zone during the Publish Interval of the new ZSK.

After the Publication Interval elapses (in our case, 2 days, 2 hours, and 10 minutes), the newly introduced ZSK starts to be used for signing other resource records:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom
current time:  Thu Dec 19 10:17:04 2024

key: 36436 (ECDSAP256SHA256), ZSK
  published:      yes - since Mon Dec 16 09:27:55 2024
  zone signing:   yes - since Wed Dec 18 11:37:55 2024

  Next rollover scheduled on Fri Feb 14 09:27:55 2025
  - goal:           omnipresent
  - dnskey:         omnipresent
  - zone rrsig:     rumoured

key: 64664 (ECDSAP256SHA256), ZSK
  published:      yes - since Thu Oct 17 09:27:55 2024
  zone signing:   no

  Key is retired, will be removed on Mon Dec 30 14:37:55 2024
  - goal:           hidden
  - dnskey:         omnipresent
  - zone rrsig:     unretentive

(output truncated)

The status of RRSIG records created by this key is set to Rumored, meaning that some resolvers may already use them, but probably not all of them.

At the same time, the old private key stops being used for signing resource records within the ns-testing.com zone. The RRSIG records associated with this key change their state to Unretentive, and they won’t be refreshed anymore. The old key also has the removal date announced. In this case, the original Retire Interval (2 days and 3 hours) is automatically extended with an additional 10 days (signatures-validity - signatures-refresh), to ensure that the old key won’t be removed before all resource records get the new signature.

During the Retire Interval, BIND gradually replaces RRSIG signatures created using the old ZSK key with the new signatures. At this stage, zone resource records may be signed by either the old, new, or even both private ZSK keys. From a DNS resolver perspective, this is a perfectly fine situation, since both public ZSK keys are sent in each DNSKEY response.

Fig.8: DNSViz graph for the ns-testing.com zone during the Retire Interval of the old ZSK key.
DNSViz graph for the ns-testing.com zone during the Retire Interval of the old ZSK key.

According to the DNSSEC policy, re-signing happens 5 days before the expiration of each RRSIG record (signatures-refresh parameter). Here is an example of the re-signing process for the www resource record.

$ dig @8.8.8.8 www.ns-testing.com. A +dnssec +multiline                                                                                                                                                                                                                                                      
; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @8.8.8.8 www.ns-testing.com. A +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53045
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;www.ns-testing.com.    IN A

;; ANSWER SECTION:
www.ns-testing.com.     3600 IN A 51.137.105.102
www.ns-testing.com.     3600 IN A 98.71.216.161
www.ns-testing.com.     3600 IN RRSIG A 13 3 3600 (
                                20241224105702 20241209105013 64664 ns-testing.com.
                                HnfsyLQ7aqhhZcVkBXiYh3FaUb81vc/RASYqEfTt49XJ
                                J3ZVsgqTIwEyXIV1N8FYDZqtkUv5is32nAOPzJqwWQ== )

;; Query time: 88 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Dec 19 11:52:41 CET 2024
;; MSG SIZE  rcvd: 189


$ dig @8.8.8.8 www.ns-testing.com. A +dnssec +multiline

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @8.8.8.8 www.ns-testing.com. A +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32633
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;www.ns-testing.com.    IN A

;; ANSWER SECTION:
www.ns-testing.com.     3600 IN A 51.137.105.102
www.ns-testing.com.     3600 IN A 98.71.216.161
www.ns-testing.com.     3600 IN RRSIG A 13 3 3600 (
                                20250103101057 20241219095702 36436 ns-testing.com.
                                aZCRKx4Mp0ZjITId75D/BH2diAORWSzGRKxjjFK8Rv0a
                                9vnJH2VZsOwIXVP5zLnpmt2dRlPf0Dbwth3n0XN4gQ== )

;; Query time: 81 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Dec 19 12:29:59 CET 2024
;; MSG SIZE  rcvd: 189

Finally, when all resource records are resigned and the old ZSK key is not used by any RRSIG record, BIND can proceed with removing that key from the zone. On the other hand, the state of RRSIG records associated with the new ZSK key changes from Rumored to Omnipresent:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom
current time:  Sat Dec 28 12:43:28 2024

key: 36436 (ECDSAP256SHA256), ZSK
  published:      yes - since Mon Dec 16 09:27:55 2024
  zone signing:   yes - since Wed Dec 18 11:37:55 2024

  Next rollover scheduled on Fri Feb 14 09:27:55 2025
  - goal:           omnipresent
  - dnskey:         omnipresent
  - zone rrsig:     omnipresent

(output truncated)

In reality, BIND doesn’t always wait for the Delete event, as defined in the private key file (in our case, Mon Dec 30 14:37:55 2024). If the zone is already free of any old RRSIGs and the Retire Interval has already elapsed, the key can be removed earlier, as shown in the /var/log/syslog snippet:

Dec 28 12:27:55 dns1 named[588]: zone ns-testing.com/IN (signed): reconfiguring zone keys
Dec 28 12:27:55 dns1 named[588]: Removing expired key ns-testing.com/64664/ECDSAP256SHA256 from DNSKEY RRset.
Dec 28 12:27:55 dns1 named[588]: DNSKEY ns-testing.com/ECDSAP256SHA256/64664 (ZSK) is now deleted

From that moment, only the new ZSK key is present in the zone:

$ dig @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54380
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;ns-testing.com.                IN DNSKEY

;; ANSWER SECTION:
ns-testing.com.         600 IN DNSKEY 257 3 13 (
                                xStQGvplWIM7roZyXLyKfkMWOSgVs5qcbwCoP0B0tlLW
                                dG+/pai0CPNu6Bs4UJaJtA1Q+YEpglSo/txjOGtzHg==
                                ) ; KSK; alg = ECDSAP256SHA256 ; key id = 54249
ns-testing.com.         600 IN DNSKEY 256 3 13 (
                                vbK10NMUWFVQuR+9otsNwiTL4LuzxRoxEWRqySb+2mhs
                                2yDyAoI1QpmiE0Ntxbs55KTx7UMekX6qQ0FIgqTEXA==
                                ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 36436
ns-testing.com.         600 IN RRSIG DNSKEY 13 2 600 (
                                20250112122755 20241228112755 54249 ns-testing.com.
                                4VyLdvQmX+mALknG27Shr/2gSjuSZOK3DRdXIn4UpNtt
                                +5hVWh7gck7eKSNgDvfVn2hJSdmlwuecgIHFDW8eZw== )

;; Query time: 83 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Dec 28 16:14:26 CET 2024
;; MSG SIZE  rcvd: 313
Fig.9: DNSViz graph for the ns-testing.com zone after the ZSK rollover.
DNSViz graph for the ns-testing.com zone after the ZSK rollover.

KSK rollover

The following rndc output shows the initial status of the KSK key within the ns-testing.com zone:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom

(output omitted)

key: 54249 (ECDSAP256SHA256), KSK
  published:      yes - since Fri Jun 21 11:37:55 2024
  key signing:    yes - since Fri Jun 21 11:37:55 2024

  Next rollover scheduled on Thu Jun 19 09:27:55 2025
  - goal:           omnipresent
  - dnskey:         omnipresent
  - ds:             omnipresent
  - key rrsig:      omnipresent

As in the previous example, the ID of the current key and its scheduled rollover date are marked in red. However, this time, instead of waiting for the scheduled time, a manual rollover is initiated:

$ sudo rndc dnssec -rollover -key 54249 ns-testing.com
Key 54249: Rollover scheduled on 02-Jan-2025 10:29:12.000

Regardless of how the rollover is initiated, in the first step BIND creates a new KSK key pair (ID 35048) and immediately publishes the respective DNSKEY record:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom

(output omitted)

key: 54249 (ECDSAP256SHA256), KSK
  published:      yes - since Fri Jun 21 11:37:55 2024
  key signing:    yes - since Fri Jun 21 11:37:55 2024

  Key will retire on Wed Jan  8 12:49:12 2025
  - goal:           hidden
  - dnskey:         omnipresent
  - ds:             omnipresent
  - key rrsig:      omnipresent

key: 35048 (ECDSAP256SHA256), KSK
  published:      yes - since Thu Jan  2 10:29:12 2025
  key signing:    yes - since Thu Jan  2 10:29:12 2025

  Next rollover scheduled on Fri Jan  2 10:29:12 2026
  - goal:           omnipresent
  - dnskey:         rumoured
  - ds:             hidden
  - key rrsig:      rumoured

The new private key is also used to sign the DNSKEY RRset along with the current key. States of DNSSEC records associated with the old key don’t change at this point and remain Omnipresent. DNSKEY and RRSIG states of the new key are set to Rumoured, and the DS record remains Hidden. The old key will retire (be removed) after the Publish Interval (2 days, 2 hours, 10 minutes) + the Retire Interval (4 days and 10 minutes).

The output below shows the newly added DNSSEC record containing the new public key (ID 35048), as well as the new RRSIG record referencing that ID - both marked in red.

$ dig @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33711
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;ns-testing.com.                IN DNSKEY

;; ANSWER SECTION:
ns-testing.com.         600 IN DNSKEY 256 3 13 (
                                vbK10NMUWFVQuR+9otsNwiTL4LuzxRoxEWRqySb+2mhs
                                2yDyAoI1QpmiE0Ntxbs55KTx7UMekX6qQ0FIgqTEXA==
                                ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 36436
ns-testing.com.         600 IN DNSKEY 257 3 13 (
                                3rbXHwkts6CgHDZkNFY1hPamWdU/m62PTOdDOue6Jc2O
                                HogSNiyw3qnOvx1oYS8vn9UFcUZ5pskSzAJ9H4UxeQ==
                                ) ; KSK; alg = ECDSAP256SHA256 ; key id = 35048
ns-testing.com.         600 IN DNSKEY 257 3 13 (
                                xStQGvplWIM7roZyXLyKfkMWOSgVs5qcbwCoP0B0tlLW
                                dG+/pai0CPNu6Bs4UJaJtA1Q+YEpglSo/txjOGtzHg==
                                ) ; KSK; alg = ECDSAP256SHA256 ; key id = 54249
ns-testing.com.         600 IN RRSIG DNSKEY 13 2 600 (
                                20250117102912 20250102092912 54249 ns-testing.com.
                                oIgD8h96iG/JlSyOoetgNjZm7zmFqSUp6VHTJEmGJjeX
                                n386XCkas0E0ZSrt6yfgIT6qaGuBgMm+xK2kptH99w== )
ns-testing.com.         600 IN RRSIG DNSKEY 13 2 600 (
                                20250117102912 20250102092912 35048 ns-testing.com.
                                9f9/ArBqbsfkY3YcnvFuxR2wlfrAfWukSwobFHKY02RH
                                zer8Pb2m0yjz3ZndPP+CUAg+m6kiiMEYXZlsMPKJLA== )

;; Query time: 61 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Jan 02 11:35:21 CET 2025
;; MSG SIZE  rcvd: 503

DNSViz graph (Figure 10) shows the current situation in the zone. The new KSK, besides signing the DNSKEY RRset, is also used to sign CDS/CDNSKEY records. The DS record at the parent zone still points at the old key. The same goes for the CDS/CDNSKEY resource records (grey arrows):

Fig.10: DNSViz graph for the ns-testing.com zone during the Publish Interval of the new KSK key.
DNSViz graph for the ns-testing.com zone during the Publish Interval of the new KSK key.

If we take a look at the timing information of the new KSK key, we will see that BIND plans to publish CDS/CDNSKEY records for that key at the time of its activation.

$ sudo dnssec-settime -p all /var/cache/bind/Kns-testing.com.+013+35048
Created: Thu Jan  2 10:29:12 2025
Publish: Thu Jan  2 10:29:12 2025
Activate: Sat Jan  4 12:39:12 2025
Revoke: UNSET
Inactive: Sun Jan  4 12:39:12 2026
Delete: Thu Jan  8 12:49:12 2026
SYNC Publish: Sat Jan  4 12:39:12 2025
SYNC Delete: UNSET
DS Publish: UNSET
DS Delete: UNSET
DS Delete: UNSET

The DNS registrar used in this example doesn’t support any automation when it comes to changes in DS records, so the publication of new CDS/CDNSKEY records doesn’t have any effect. Instead, a manual change needs to be made when the Publish Interval elapses. However, since the DNSKEY RRset TTL is rather short (only 10 min.) and the synchronization between the primary and the secondary DNS server hosting the ns-testing.com zone is almost instantaneous, we can change the DS records much earlier. It also wouldn’t be a problem if we delayed changing the DS record and did it in the middle of the Retire Interval, or even after the official retirement date of the old key. This is because BIND halts the whole rollover process until it knows that the DS record has been changed, and this information is propagated to all resolvers. In practice, this means that we must wait until the state of the DS record associated with the new KSK key is Omnipresent to proceed with the next step (removing the old KSK key).

To change the DS records, first of all, we need to generate their new content with the hash of the new KSK key:

$ dnssec-dsfromkey /var/cache/bind/Kns-testing.com.+013+35048.key
ns-testing.com. IN DS 35048 13 2 B88EC27A70A3EBBCA97B49A8F2A9AFADE9C77A89ABC436C07DE3C9B1C91998BF

Next, we have to log in to the registrar’s management portal and add proper information that would allow us to create the DS record:

Fig.11: Changing DS record at the parent domain level.
Changing DS record at the parent domain level.

This time, we must wait much longer for this information to be propagated over the Internet because the TTL of the DS record is six hours. During this time, there might be some resolvers using the old, cached version of the record, still pointing at the old KSK. At the same time, there might be resolvers that already use the new version of the record. In both cases, they should be able to properly validate the zone, since the DNSKEY RRset contains the old and the new public KSK key, and it is double-signed by both private keys. Eventually, all resolvers should have the following content in their caches:

$ dig @8.8.8.8 ns-testing.com. DS +dnssec +multiline

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @8.8.8.8 ns-testing.com. DS +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18087
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;ns-testing.com.                IN DS

;; ANSWER SECTION:
ns-testing.com.         21600 IN DS 35048 13 2 (
                                B88EC27A70A3EBBCA97B49A8F2A9AFADE9C77A89ABC4
                                36C07DE3C9B1C91998BF )
ns-testing.com.         21600 IN RRSIG DS 13 2 86400 (
                                20250109120335 20250102105335 29942 com.
                                rLxIrYs0lJNqrnRcAcJB6RE7EzCyr1VBTsR0917wbMLP
                                rkry6g8XBqQ5Xa4/WjHvNU1iE1ISuVYGjGc4w46G+g== )

When the Publish Interval elapses, we should see some changes in the DNSSEC records’ states:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom

(output omitted)

key: 54249 (ECDSAP256SHA256), KSK
  published:      yes - since Fri Jun 21 11:37:55 2024
  key signing:    yes - since Fri Jun 21 11:37:55 2024

  Key will retire on Wed Jan  8 12:49:12 2025
  - goal:           hidden
  - dnskey:         omnipresent
  - ds:             unretentive
  - key rrsig:      omnipresent

key: 35048 (ECDSAP256SHA256), KSK
  published:      yes - since Thu Jan  2 10:29:12 2025
  key signing:    yes - since Thu Jan  2 10:29:12 2025

  Next rollover scheduled on Fri Jan  2 10:29:12 2026
  - goal:           omnipresent
  - dnskey:         omnipresent
  - ds:             rumoured
  - key rrsig:      omnipresent

The DS record of the old KSK key goes to the Unretentive state. DNSKEY and RRSIG records of the new key change their states from Rumoured to Omnipresent, while its DS record becomes Rumoured (see Figure 3 for reference). Note that changes in DS records states have nothing to do with actual modifications at the parent zone. Instead, they are strictly related to state changes of associated keys.

At this point, when we take a look at the DNSViz graph, we will see that the new KSK has trust with the parent zone. CDS/CDNSKEY records also point to the new KSK key. The old key is still present and it will be kept at least for the Retire Interval.

Fig.12: DNSViz graph for the ns-testing.com zone during the Retire Interval of the old KSK key.
DNSViz graph for the ns-testing.com zone during the Retire Interval of the old KSK key.

Since we don’t have any parental agents configured, we must manually inform BIND that the DS record for the new KSK key has been published and the old one has been removed:

$ sudo rndc dnssec -checkds -key 35048 published ns-testing.com
$ sudo rndc dnssec -checkds -key 54249 withdrawn ns-testing.com

Information about DS records publication and withdrawal is also included in key timing information:

$ sudo dnssec-settime -p all /var/cache/bind/Kns-testing.com.+013+54249
Created: Fri Jun 21 11:37:55 2024
Publish: Fri Jun 21 11:37:55 2024
Activate: Fri Jun 21 11:37:55 2024
Revoke: UNSET
Inactive: Sat Jan  4 12:39:12 2025
Delete: Wed Jan  8 12:49:12 2025
SYNC Publish: Sun Jun 23 14:37:55 2024
SYNC Delete: UNSET
DS Publish: Fri Jun 21 17:47:09 2024
DS Delete: Thu Jan  4 12:51:44 2025

$ sudo dnssec-settime -p all /var/cache/bind/Kns-testing.com.+013+35048
Created: Thu Jan  2 10:29:12 2025
Publish: Thu Jan  2 10:29:12 2025
Activate: Sat Jan  4 12:39:12 2025
Revoke: UNSET
Inactive: Sun Jan  4 12:39:12 2026
Delete: Thu Jan  8 12:49:12 2026
SYNC Publish: Sat Jan  4 12:39:12 2025
SYNC Delete: UNSET
DS Publish: Thu Jan  4 12:51:36 2025
DS Delete: UNSET

Issuing both commands doesn’t immediately change the states of the respective DS records. BIND waits for an additional Retire Interval before moving the new DS record to the Omnipresent state and the old DS record to the Hidden state.

When the status of the DS record associated with the new KSK key changes to Omnipresent, the old KSK key is finally retired and removed from the DNSKEY RRset. All DNSSEC records associated with that key become Unretentive:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom

(output omitted)

key: 54249 (ECDSAP256SHA256), KSK
  published:      no
  key signing:    no

  Key has been removed from the zone
  - goal:           hidden
  - dnskey:         unretentive
  - ds:             unretentive
  - key rrsig:      unretentive

key: 35048 (ECDSAP256SHA256), KSK
  published:      yes - since Thu Jan  2 10:29:12 2025
  key signing:    yes - since Thu Jan  2 10:29:12 2025

  Next rollover scheduled on Fri Jan  2 10:29:12 2026
  - goal:           omnipresent
  - dnskey:         omnipresent
  - ds:             omnipresent
  - key rrsig:      omnipresent

If we query for a DNSKEY resource record, we will see only one KSK key (the active one):

$ dig @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @8.8.8.8 ns-testing.com. DNSKEY +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63617
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;ns-testing.com.                IN DNSKEY

;; ANSWER SECTION:
ns-testing.com.         600 IN DNSKEY 256 3 13 (
                                vbK10NMUWFVQuR+9otsNwiTL4LuzxRoxEWRqySb+2mhs
                                2yDyAoI1QpmiE0Ntxbs55KTx7UMekX6qQ0FIgqTEXA==
                                ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 36436
ns-testing.com.         600 IN DNSKEY 257 3 13 (
                                3rbXHwkts6CgHDZkNFY1hPamWdU/m62PTOdDOue6Jc2O
                                HogSNiyw3qnOvx1oYS8vn9UFcUZ5pskSzAJ9H4UxeQ==
                                ) ; KSK; alg = ECDSAP256SHA256 ; key id = 35048
ns-testing.com.         600 IN RRSIG DNSKEY 13 2 600 (
                                20250117122544 20250102112544 35048 ns-testing.com.
                                WITkC65hCKCisB+T3mLHWfxh/1hssXL0glJ7Tg6vLSMP
                                Z18F6CxPCmx8Io6rh5uxEsEp71l7NZaO+UPCbvtKdw== )

;; Query time: 62 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Jan 09 13:06:46 CET 2025
;; MSG SIZE  rcvd: 313

The DNSViz graph will show only one KSK key in the zone.

Fig.13: DNSViz graph for the ns-testing.com zone after the KSK rollover.
DNSViz graph for the ns-testing.com zone after the KSK rollover.

As time passes, all DNSSEC records related to the old KSK key should become Hidden, meaning that they are not visible to anyone. The final state of the keys participating in the rollover will be as follows:

$ sudo rndc dnssec -status ns-testing.com
dnssec-policy: custom

(output omitted)

key: 54249 (ECDSAP256SHA256), KSK
  published:      no
  key signing:    no

  Key has been removed from the zone
  - goal:           hidden
  - dnskey:         hidden
  - ds:             hidden
  - key rrsig:      hidden

key: 35048 (ECDSAP256SHA256), KSK
  published:      yes - since Thu Jan  2 10:29:12 2025
  key signing:    yes - since Thu Jan  2 10:29:12 2025

  Next rollover scheduled on Fri Jan  2 10:29:12 2026
  - goal:           omnipresent
  - dnskey:         omnipresent
  - ds:             omnipresent
  - key rrsig:      omnipresent

Key takeaways

In this article, we focused on the practical side of DNSSEC key management. We explored how BIND handles DNSSEC using Key and Signing Policy (KASP), including the lifecycle of keys, file structures, state transitions, and the timing of rollover events. Finally, we demonstrated real-life rollover examples, showing step-by-step how ZSK and KSK transitions are executed safely in a BIND environment.

Hryszko  Mariusz

Mariusz Hryszko

Network Engineer

Mariusz Hryszko is a network engineer and author on CodiLime's blog. Check out the author's articles on the blog.Read about author >

Read also

Get your project estimate

For businesses that need support in their software or network engineering projects, please fill in the form and we'll get back to you within one business day.