DNS and DNSSEC

Emergency DNSSEC key revocation, the secure way

There is no revocation list in DNSSEC. When a key leaks, "revoke" means replacing it faster than the attacker can use it, in an order that does not take your own zone down first.

The short answer

For a leaked ZSK, activate a new ZSK now, retire the old one now, and remove it after the DNSKEY TTL; no registrar is involved. For a leaked KSK, add a new KSK, replace the DS at the registrar, wait the parent's DS TTL, then remove the old KSK. Deleting it first leaves the zone bogus and spoofable.

Updated Houssam Hammoudi, CTOTested with Knot DNS 3.5.4, BIND delv 9.20.29

On this page
  1. What goes wrong
  2. What the docs say
  3. The secure configuration
  4. Prove it
  5. Mistakes people make
  6. Checklist

What goes wrong

A certificate can be revoked. A DNSSEC key cannot. Validators trust a key while two things hold: the DNSKEY set that contains it has a valid signature, and the chain above it (the DS at the parent) points to a key that signed that set. To take a leaked key out of use, you change the key set and, for a KSK, the DS.

The ZSK case is local and quick. The KSK case needs the registrar, and most teams have never done it under pressure. Two opposite mistakes are common. Some teams wait for the next planned rollover, which leaves the stolen key valid for weeks. Others delete the leaked KSK at once. The DS at the parent still points to it, so the zone turns bogus for every validating resolver, and the attacker, who holds the key the DS points to, can still sign a version that validates.

What the docs say

When the private material of one of a zone's keys is compromised, it can be used by an attacker for as long as a valid trust chain exists.

Source: RFC 6781, Section 4.2

Note that until that time, the child zone is still vulnerable to spoofing: The attacker is still in possession of the compromised key that the DS points to.

Source: RFC 6781, Section 4.2.1.2

Therefore, we advise administrators not to remove the KSK before the parent has a DS record for the new KSK in place.

Source: RFC 6781, Section 4.2.1

The revoke state can only be established using keymgr when using Manual key management.

Source: Knot DNS 3.5 docs, DNSSEC key states

The RFC explains the trade-offs well. Knot's docs describe the key states and timers but have no emergency runbook; the procedure below is built from keymgr timers. The "revoke" state in Knot is the RFC 5011 REVOKE bit. It only matters to resolvers that use your key as a configured trust anchor. For a normal delegated zone, the DS at the parent is what counts.

The secure configuration

Prepare before anything leaks:

yaml
policy:
  - id: secure
    algorithm: ecdsap256sha256
    dnskey-ttl: 3600               # the ZSK swap waits this long; keep it modest
    zone-max-ttl: 3600
    rrsig-lifetime: 14d            # a replayed old DNSKEY set is valid at most this long
    rrsig-refresh: 7d
  • Know the parent's DS TTL (kdig example.com DS @<parent server> +norecurse).
  • Know how to change the DS at the registrar, who can do it, and whether it needs a second factor that sits in someone's drawer.
  • During an incident, switch the zone to manual key management (manual: on) so no automatic step fights your timers.

Runbook A: ZSK compromised

bash
# 1. New ZSK: published and signing now.
keymgr example.com generate algorithm=ecdsap256sha256 ksk=no zsk=yes publish=+0 active=+0

# 2. Old ZSK: stop signing now, leave the DNSKEY set after the DNSKEY TTL (+ margin).
keymgr example.com set <old-zsk-tag> retire=+0 remove=+2h

# 3. Apply.
knotc zone-keys-load example.com

Resolvers that cached the old DNSKEY set before step 1 cannot check the new signatures until that cache entry expires (up to dnskey-ttl). Accept that short window, or wait one DNSKEY TTL between steps 1 and 2 if you can.

Runbook B: KSK compromised, chain kept intact (RFC 6781 4.2.1.1)

bash
# 1. New KSK, active now; both KSKs sign the DNSKEY set.
keymgr example.com generate algorithm=ecdsap256sha256 ksk=yes zsk=no publish=+0 ready=+0 active=+0
knotc zone-keys-load example.com
keymgr example.com ds <new-ksk-tag>

# 2. Registrar: REPLACE the DS with the new one. Confirm at every parent server:
kdig example.com DS @<parent server> +norecurse

# 3. After the parent's DS TTL: remove the leaked KSK.
keymgr example.com set <old-ksk-tag> retire=+0 remove=+0
knotc zone-keys-load example.com

Last resort: go insecure on purpose

If the registrar cannot publish a new DS quickly, ask it to remove the DS. The zone becomes insecure (unsigned to validators), not bogus. Then rebuild keys and submit a new DS. This is the second method in RFC 6781 4.2.1.2.

Prove it

The test (secure-tests/emergency-dnssec-key-revocation/run.sh) runs Knot with stand-in com. and net. parent zones. A TSIG key named registrar plays the registrar. Both child zones use manual key management and 5-second TTLs. Both validate at the start:

text
[21:11:32] $ delv @127.0.0.1 -a anchor.conf +root=com www.example.com A
; fully validated

[21:11:32] $ delv @127.0.0.1 -a anchor.conf +root=net www.example.net A
; fully validated

Runbook A on example.com: ZSK 40433 leaked

text
$ keymgr example.com generate algorithm=ecdsap256sha256 ksk=no zsk=yes publish=+0 active=+0
$ keymgr example.com set 40433 retire=+0 remove=+10     # stop signing now; unpublish after DNSKEY TTL + margin
OK
$ knotc zone-keys-load example.com
OK
[21:11:34] $ kdig @127.0.0.1 www.example.com A +dnssec +norecurse +noall +answer   (RRSIG key tag)
RRSIG A by key 44627

[21:11:34] $ kdig @127.0.0.1 example.com DNSKEY +norecurse +short | cut -c1-40
256 3 13 FQcTsieAgvqGjNITAWqa4TVwLFXl5ee
256 3 13 8Xbd0c44ODJ3kYmU5TnIvKLSpZQNUIb
257 3 13 gBAAWXNVi0YLRwLQe04RMPQZCgVHw7o

[21:11:34] $ delv @127.0.0.1 -a anchor.conf +root=com www.example.com A
; fully validated

Signing moved to the new key at once. After the DNSKEY TTL, the leaked key is gone from the set, and the zone still validates:

text
[21:11:46] $ kdig @127.0.0.1 example.com DNSKEY +norecurse +short | cut -c1-40
256 3 13 FQcTsieAgvqGjNITAWqa4TVwLFXl5ee
257 3 13 gBAAWXNVi0YLRwLQe04RMPQZCgVHw7o

[21:11:46] $ delv @127.0.0.1 -a anchor.conf +root=com www.example.com A
; fully validated

Runbook B on example.com: KSK 22226 leaked

text
Step 1: add a new KSK next to the compromised one
$ keymgr example.com generate algorithm=ecdsap256sha256 ksk=yes zsk=no publish=+0 ready=+0 active=+0
[21:11:49] $ kdig @127.0.0.1 example.com DNSKEY +norecurse +short | cut -c1-40
256 3 13 FQcTsieAgvqGjNITAWqa4TVwLFXl5ee
257 3 13 gBAAWXNVi0YLRwLQe04RMPQZCgVHw7o
257 3 13 yfTyuROhPaALYuDVsTDXdGPD5umro44

Step 2: REGISTRAR: replace the DS (old 22226 -> new 15500)
$ kdig @127.0.0.1 example.com DS +short
15500 13 2 F5ABFB4435A20B4C10BC81121B37F618ABD3F812EA8DA24322A4139F2D5DDAED

[21:11:49] $ delv @127.0.0.1 -a anchor.conf +root=com www.example.com A
; fully validated

Step 3: after the parent's DS TTL (5 s in the lab), remove the compromised KSK
$ keymgr example.com set 22226 retire=+0 remove=+0
OK
[21:11:57] $ kdig @127.0.0.1 example.com DNSKEY +norecurse +short | cut -c1-40
256 3 13 FQcTsieAgvqGjNITAWqa4TVwLFXl5ee
257 3 13 yfTyuROhPaALYuDVsTDXdGPD5umro44

[21:11:57] $ delv @127.0.0.1 -a anchor.conf +root=com www.example.com A
; fully validated

The chain stayed valid at every step, and the leaked KSK is out of both the DNSKEY set and the parent.

The panic path on example.net

A new KSK is added, and the leaked KSK 13750 is removed before anyone touched the registrar. The parent still points to it:

text
$ keymgr example.net set 13750 retire=+0 remove=+0     # before the registrar changed anything
OK
$ kdig @127.0.0.1 example.net DS +short
13750 13 2 F6E8E548CFD26DD6E125162F8E0F116398158CA617EA49EE15D41755E242301F

[21:11:59] $ kdig @127.0.0.1 example.net DNSKEY +norecurse +short | cut -c1-40
256 3 13 9OGKatztjDItr5pRo1rSpmEL0LobSgh
257 3 13 POBToLJz5rCCHlJOyXSXYTj2wK23gCq

[21:11:59] $ delv @127.0.0.1 -a anchor.conf +root=net www.example.net A
;; validating example.net/DNSKEY: no valid signature found (DS)
;; no valid RRSIG resolving 'example.net/DNSKEY/IN': 127.0.0.1#53

The real zone is now bogus. The DS still names the leaked key, so a copy of the zone signed with that key would still validate.

Mistakes people make

Deleting the leaked KSK first

It feels like the safe move. It is the only move that hurts you twice: your zone fails validation, and the attacker's copy does not. Add the new KSK, change the DS, then remove.

Forgetting the old DNSKEY set can be replayed

After a ZSK leak, an attacker can serve your old DNSKEY set, with its valid KSK signature, alongside records signed by the stolen ZSK. RFC 6781 notes a trust chain stays usable "as long as a signature over the compromised key in the trust chain is valid". That window is your DNSKEY signature lifetime. Keep rrsig-lifetime moderate, and treat a leak of the KASP database (which holds both keys) as a KSK compromise.

Using the revoke bit for a delegated zone

Setting REVOKE on a KSK tells RFC 5011 trust-anchor clients to stop trusting it. Ordinary resolvers follow the DS instead. For a normal zone, the DS change is the revocation.

Discovering the registrar process during the incident

Registrar logins with hardware tokens, change locks and support tickets can turn minutes into days. Rehearse a DS change once a year on a test domain, and write down the steps.

Letting automatic key management run during the incident

An automatic policy can start its own rollover or regenerate keys while you are setting timers. Switch the zone to manual: on for the incident, and switch back after.

Checklist

  • Write the two runbooks (ZSK and KSK) before you need them.
  • Record the parent's DS TTL for each zone.
  • Test a DS change at the registrar at least once a year.
  • Keep rrsig-lifetime and dnskey-ttl at values you can wait out.
  • On a ZSK leak: new ZSK active=+0, old ZSK retire=+0, remove after the DNSKEY TTL.
  • On a KSK leak: add the new KSK, replace the DS, wait the parent's DS TTL, then remove the old KSK.
  • Treat a leaked KASP database as a KSK compromise.
  • Validate with delv after every step.
  • If the registrar cannot change the DS quickly, ask it to remove the DS and go insecure, not bogus.
  • Rotate the TSIG and registrar credentials that were stored with the leaked keys.

In DNSSEC, revocation is a sequence, not a button. Run the sequence in the right order and the only people who notice are the ones holding the old key.

H2-CPQE

Learn it on a live range

DNSSEC with Knot, in Edge and Post-Quantum Networking: a real host in your browser, and every objective checked on the machine.

Start free

The Dome

Want it run for you?

The Dome puts post-quantum TLS, a WAF that blocks, signed DNS and a zero-trust mesh in front of your application. Tell us what you run.

See the Dome