Whenever a DNSSEC-signed zone changes its trust anchor — typically a Key Signing Key (KSK) — the delegation signer (DS) record has to be communicated to the parent zone via some API. RFC 7344 describes how this DNSSEC Delegation Trust Maintenance can be automated via the DNS itself:
…a technique in which the Parent periodically (or upon request) polls its signed Children and automatically publishes new DS records.RFC 7344
Two record types (CDS and CDNSKEY, from now on written as CDS) are used to convey the desired DS state from the child zone to its parent. The records are published in the child zone (manually or automatically) and indicate what the child would like the DS RRset to look like after the change. A parent consumes the child DS (CDS) records and replaces (by whichever means it needs to) the DS RRset in the parent zone.
There are typically three operations that a child zone wishes its parent to perform:
- Enable validation, such as store an initial DS RRset in the parent.
- Roll over the zone trust anchor (typically a KSK), which means updating the DS in the parent or change hashing algorithms, such as during the SHA-1 deprecation.
- Disable DNSSEC validation entirely, specifically, delete all DS records for the child, in the parent.
I first worked with CDS/CDNSKEY in 2017, and I think it was in 2018 that I visited SWITCH and met Michael, Daniel, and Oli who explained they were working on a mechanism to permit holders of
.li domains to use CDS/CDNSKEY to upload the DS to the parent, something which was already possible in
.cz. I thought this quite exciting and have since mentioned SWITCH doing this several times.
It occurred to me a few weeks ago, when I was again explaining the benefits of CDS, that I’d never actually experienced the SWITCH system in operation. Instead of going out for a quick meal I spent the equivalent on a Swiss domain name with which to experiment, with the added benefit that it’s calorie-free.
SWITCH have laid out exact acceptance criteria in well-written guidelines for CDS processing at SWITCH, and they include criteria for bootstrapping a first CDS upload:
- CDS records must be consistently published for three consecutive days, and any change in the RRset resets the counter.
- All name servers must be reachable over TCP and deliver a consistent CDS RRset.
Being an impatient person, I thought I’d make sure CDS is published first and then register the domain, hoping that the initial query of the registry would detect CDS and automatically begin the three-day cycle.
So I create a trust anchor key for my zone and set CDS publishing to ten minutes in the future in order to test the idea a user suggested during a BIND webinar — log CDS publication so external programs can react to it.
$ dnssec-keygen -a 13 -P sync now+10mi tcp53.ch Generating key pair. Ktcp53.ch.+013+02132 $ cat Ktcp53.ch.+013+02132.key ; This is a zone-signing key, keyid 2132, for tcp53.ch. ; Created: 20210918195720 (Sat Sep 18 19:57:20 2021) ; Publish: 20210918195720 (Sat Sep 18 19:57:20 2021) ; Activate: 20210918195720 (Sat Sep 18 19:57:20 2021) ; SyncPublish: 20210918200925 (Sat Sep 18 20:09:25 2021) tcp53.ch. IN DNSKEY 256 3 13 1jv8eUuJ+alGvnAh2aQjxm27pez3aR62DTmDMwDxkcqJvpkCP4FGhrLj 4E+21hqUSa50XJ2VcimQqFL5RyPlLA==
If you’re wondering why that’s a ZSK that flags 256, no need to wonder — it’s perfectly legal; it’s a single signing key, and there’s a well-known precedent for doing this:
Minutes later I observe BIND logging CDS publication:
18-Sep-2021 20:09:25.641 CDS for key tcp53.ch/ECDSAP256SHA256/2132 is now published 18-Sep-2021 20:09:25.641 CDNSKEY for key tcp53.ch/ECDSAP256SHA256/2132 is now published
And I can query CDS (and CDNSKEY) in the zone:
$ dig @::1 tcp53.ch CDS +norec ;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; ANSWER SECTION: tcp53.ch. 3600 IN CDS 2132 13 2 7B895D35CC8F5A6EBD7C2BBED8738487084322DE22622E13FBF99FE6 5FEA20BB
I register the domain via my registrar, and as soon as that’s done, I impatiently check the status of CDS publication:
I’ll have to wait so I call it an evening and relax, assuming the robot does its thing at 06:00 UTC. Sunday morning at about 08:00 UTC, excited and refreshed, I check again and am confronted with the same message. Does the Swiss robot not work on Sundays? I wake Oli to ask him. It turns out there are two robots. The first rises early to collect CDS/CDNSKEY and RRSIG from distinct vantage points, and the second robot sleeps in a bit before comparing the scan results and performs required checks, tracking the state of each domain, and updating the information presented on the web page.
That looks quite good to me. They’ve noticed we’re bootstrapping, the state is PENDING, which likely means no DS is copied to the parent yet, and we’re on the first verification.
The disadvantage of this initial bootstrapping is that it’s going to take at least three days before the DS lands in the parent. It’s not a problem in this case, but if I want a zone signed immediately, I’d have to bootstrap via my registrar which, for me, is a copy/paste activity and an email.
While waiting, I also want to remind you that CDS automation with Knot-DNS is also possible. When a zone is signed, Knot publishes CDS records and uploads the hashes as DS records to the parent’s server via a dynamic DNS update
So, after waiting the required 72 hours, I finally get to see the result on the CDS status page, but I have to wait a publishing cycle for the DS to actually show up in the parent .CH zone.
;; ANSWER SECTION: tcp53.ch. 3600 IN DS 2132 13 2 ( 7B895D35CC8F5A6EBD7C2BBED8738487084322DE2262 2E13FBF99FE65FEA20BB )
The zone now validates:
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; ANSWER SECTION: tcp53.ch. 3567 IN RP . jpm.people.dnslab.org. tcp53.ch. 3567 IN RRSIG RP 13 2 3600 ( 20211006101141 20210922052438 2132 tcp53.ch. [omitted] )
I’m not a great believer in DNSSEC key rollovers (I don’t typically roll my SSH or house keys either), but I want to see how this works at .CH, so I generate a new key and kick the signer.
$ dnssec-keygen -K . -a 13 -P sync now+2mi tcp53.ch Generating key pair. Ktcp53.ch.+013+12909 $ cat Ktcp53.ch.+013+12909.key ; This is a zone-signing key, keyid 12909, for tcp53.ch. ; Created: 20210922082733 (Wed Sep 22 08:27:33 2021) ; Publish: 20210922082733 (Wed Sep 22 08:27:33 2021) ; Activate: 20210922082733 (Wed Sep 22 08:27:33 2021) ; SyncPublish: 20210922082933 (Wed Sep 22 08:29:33 2021) tcp53.ch. IN DNSKEY 256 3 13 MGNbmcOycYHQpbQtli+VAIZwMkYCLBSSrStl5WjqBsV3VZBugy4a71SL FSKlkstj/h4OKjqBBkwAin6DCNUVeA== $ rndc sign tcp53.ch $ tail -5 dnssec.log 22-Sep-2021 08:29:47.105 Fetching tcp53.ch/ECDSAP256SHA256/12909 (ZSK) from key repository. 22-Sep-2021 08:29:47.105 DNSKEY tcp53.ch/ECDSAP256SHA256/12909 (ZSK) is now published 22-Sep-2021 08:29:47.105 DNSKEY tcp53.ch/ECDSAP256SHA256/12909 (ZSK) is now active 22-Sep-2021 08:29:47.105 CDS for key tcp53.ch/ECDSAP256SHA256/12909 is now published 22-Sep-2021 08:29:47.105 CDNSKEY for key tcp53.ch/ECDSAP256SHA256/12909 is now published $ dig @::1 tcp53.ch CDS +nocrypto ;; ANSWER SECTION: tcp53.ch. 3600 IN CDS 2132 13 2 [omitted] tcp53.ch. 3600 IN CDS 12909 13 2 [omitted]
At 08:50 on the morning after creating the second key and publishing its CDS I check the status and the robot has already obtained the set:
At 09:12 CEST, I notice a change in the .CH Start of Authority (SOA) serial number and query them to find both our DS records in the parent. As the zone is signed and SWITCH can validate the CDS as it already trusts the child, the import of the additional DS can be done without further difficulty.
I will now remove the first key (2132) from the zone and unpublish its CDS, and expect no problems with that. The result will be that the parent reflects the deleted CDS in their DS RRset.
$ dnssec-settime -P ds now -D sync now -D now+3600 Ktcp53.ch.+013+02132. ./Ktcp53.ch.+013+02132.key ./Ktcp53.ch.+013+02132.private $ grep ';' Ktcp53.ch.+013+02132.key ; This is a zone-signing key, keyid 2132, for tcp53.ch. ; Created: 20210918195720 (Sat Sep 18 19:57:20 2021) ; Publish: 20210918195720 (Sat Sep 18 19:57:20 2021) ; Activate: 20210918195720 (Sat Sep 18 19:57:20 2021) ; Delete: 20210923081832 (Thu Sep 23 08:18:32 2021) ; SyncPublish: 20210918200925 (Sat Sep 18 20:09:25 2021) ; SyncDelete: 20210923071832 (Thu Sep 23 07:18:32 2021) $ rndc sign tcp53.ch $ tail -f dnssec.log 23-Sep-2021 07:19:24.189 zone tcp53.ch/IN (signed): reconfiguring zone keys 23-Sep-2021 07:19:24.189 CDS (SHA-256) for key tcp53.ch/ECDSAP256SHA256/2132 is now deleted 23-Sep-2021 07:19:24.189 CDNSKEY for key tcp53.ch/ECDSAP256SHA256/2132 is now deleted
This is the point at which I notice I’ve been mixing time zones, and I’m sorry for the confusion. Times in consoles on the server are UTC (as they ought to be), and times you see in most
dig(1) queries are in CEST, because that’s how my workstation is set up.
Change of DNS operator for a domain can be facilitated by turning off DNSSEC for it, and I want to see how this functions.
RFC 8078 section 4 describes the Delete Algorithm, which basically entails publishing a signed CDS (and/or CDNSKEY) resource record (the RRset MUST contain only one record) with the following rdata:
CDS 0 0 0 00 CDNSKEY 0 3 0 AA==
This signed CDS is validated via the DS, which is already in the parent, and as SWITCH Guidelines also remind me, DNSSEC validation for my zone must succeed in order for them to remove its trust anchor from the parent.
I tune the DNSSEC key to delete CDS/CDNSKEY records from the zone and add the ‘deletion’ CDS to it:
$ dnssec-settime -D sync now Ktcp53.ch.+013+12909. ./Ktcp53.ch.+013+12909.key ./Ktcp53.ch.+013+12909.private $ grep ';' Ktcp53.ch.+013+12909.key ; This is a zone-signing key, keyid 12909, for tcp53.ch. ; Created: 20210922082733 (Wed Sep 22 08:27:33 2021) ; Publish: 20210922082733 (Wed Sep 22 08:27:33 2021) ; Activate: 20210922082733 (Wed Sep 22 08:27:33 2021) ; SyncPublish: 20210922082933 (Wed Sep 22 08:29:33 2021) ; SyncDelete: 20210924170318 (Fri Sep 24 17:03:18 2021) $ tail dnssec.log 24-Sep-2021 17:04:52.825 CDS (SHA-256) for key tcp53.ch/ECDSAP256SHA256/12909 is now deleted 24-Sep-2021 17:04:52.825 CDNSKEY for key tcp53.ch/ECDSAP256SHA256/12909 is now deleted $ nsupdate -l <<E! add tcp53.ch. 60 CDS 0 0 0 00 send E!
The result is a signed Delete CDS in the zone, so I expect tomorrow’s verification to have removed DS records from the parent, effectively ‘unsigning’ the zone. (DNSSEC keys and signatures remain in the zone, but as there’s no chain of trust from the parent, validation will be skipped for my zone.)
It turns out this becomes a bit more complicated (on my side) due to a hiccup with the manually-added CDS, but I will report on that a bit later when I’ve had the time to reflect on what went wrong. To cut a long story short, I had to manually sign the zone for the manually-added Delete CDS to ‘stay’ in it.
CDS works, and it’s a good method to communicate changes to a parent zone, particularly if both parent and child are under my control: I can then use automatic DS submission like Knot provides, or use
dnssec-cds provided by BIND.
I think I understand SWITCH’s motivation for waiting three full days for bootstrapping new zones before accepting the CDS/CDNSKEY records and copying the DS into the parent zone, but it is quite a long time to wait. It’s an ‘are you really really sure you want to do this, or did you sign by mistake?’ kind of period. For all intents and purposes, the zone does not validate during this 72-hour period (note that I’m discussing the DNS method; SWITCH also uses EPP). What also works (I tested it) is that SWITCH resets the three-day counter as soon as one of the zone’s name servers doesn’t respond. The motivation for the three days was to avoid BGP hijacking issues, and this duration was chosen (instead of an even longer one) as a compromise — if my name server IP addresses are hijacked for three days without me noticing, I’m likely having much bigger issues than DNSSEC not being enabled on a zone.
I briefly hoped that RFC 8078 section 3.5 had secretly been implemented. Accept from Inception enables a parent adding a domain that is not yet delegated (at all) to use the child CDS RRset to immediately publish a DS along with the new NS RRset. It’s delegated in a secure state, so to speak. It seems to me as though this would be beneficial for those domains that can actually create keys and publish the CDS/CDNSKEY just before registering the domain, but I’m clueless as to how many that would be, percentage-wise, and whether the effort would be worthwhile.
RFC 8078‘s 3.4 Accept with Challenge might also be a viable method. I’m thinking along the lines of an HTTPS request to a well-known URL that produces a challenge that must be added to the DNS within, say, 15 minutes, before the robot queries whether it’s actually there, before consuming/ processing the CDS.
DNSSEC Bootstrapping has further reading that describes an authenticated in-band method for automatic signalling of a DNS zone’s delegation signer information from the zone’s DNS operator. I understand SWITCH is considering this for a future iteration.
Jan-Piet Mens is an independent Unix/Linux consultant and sysadmin who’s worked with Unix-systems since 1985. JP works extensively with the DNS and authored the book Alternative DNS Servers and a variety of other technical publications.
This post was originally published on jpmens.net.
The views expressed by the authors of this blog are their own and do not necessarily reflect the views of APNIC. Please note a Code of Conduct applies to this blog.