2026-09-08 · 5 min read
ds-watch: a transparency log for DNSSEC's trust chain
Certificate Transparency has watched the web PKI since 2013. DNSSEC has the same structural problem and no equivalent. I built a small observatory, ds-watch, that photographs the DNS trust chain every day and publishes every change as a public, registry-signed log. It's now running in production against three gTLD zones.
Certificate Transparency has been running since 2013: every TLS certificate a
CA issues gets logged publicly, so misissuance is caught rather than merely forbidden by policy. DNSSEC has a structurally identical problem and, twelve years later, no equivalent fix. I spent the last few weekends building one — a small observatory called ds-watch that watches the DNS trust chain and writes every change to a public log.
The problem: DS records can change and nobody notices
DNSSEC secures the DNS with a chain of signatures, root down to the zone you're actually querying. The record that connects a child zone to its parent is the DS record — it says which key is authorized to sign for the zone below. Registries and registrars control that record on the parent side, and they can replace it whenever they want — during a routine key rollover, or for any other reason, and nobody downstream finds out. The DNS keeps no history of its own trust chain. Once a DS record is swapped, the previous one is simply gone, and there's no built-in way for the domain owner, or anyone else, to notice.
Why adoption is stuck
A handful of IETF standards would let domains anchor real cryptographic identity in DNS instead of relying on a CA. DANE (RFC 6698) publishes a server's TLS key directly in its own zone; RFC 7672 does the same for SMTP. SMIMEA (RFC 8162) lets anyone look up your S/MIME certificate from your email address and send you encrypted mail without a prior key exchange. DANCE extends the idea to client certificates.
Adoption is thin. DANE for mail has decent traction among European providers; SMIMEA is mostly a curiosity; the rest is paperware. Some of that is ordinary chicken-and-egg, but I think there's a structural reason underneath it too: all of these standards depend on the DS chain, and the DS chain isn't observable. If a trust anchor gets swapped — by a compromised registrar account, or a mistake, or anything else — there's currently no way to know, for anyone. Anchoring your email security on an unmonitored chain of custody is a bad trade, and it's a reasonable thing to hold off on until that's not true anymore. That's the same trade the web PKI used to force on everyone, until Certificate Transparency made the CA side of it checkable in 2013. Nobody's done the equivalent for DNSSEC.
What ds-watch actually does
Once a day, per zone, it runs a fixed pipeline:
- Fetch. Download the full zone file from ICANN's Centralized Zone Data
Service, at most once per zone per 24 hours — the client checks Last-Modified and enforces the minimum interval in code, not just by convention.
- Extract. Stream-parse the DS, DNSKEY and RRSIG records out of the
file — the raw zone text is never held in memory, though the extracted records for a zone the size of .org still add up to a few hundred MB while the snapshot is being written.
- Diff. Compare the new snapshot against yesterday's, per delegation,
producing three event types: ds_added (DNSSEC turned on), ds_removed (the delegation went insecure — the signal that matters most), ds_changed (rollover or silent key swap).
- Publish. Write the events plus a daily aggregate to an append-only
history, each day's aggregate hash-chained to the one before it, and commit to git.
The most likely failure mode is a truncated download, and a truncated download looks exactly like a mass ds_removed event if you're not careful. So there's a sanity gate: if the DS count drops implausibly or the zone file looks suspiciously small, the run is quarantined instead of published.
Every event carries its own evidence rather than just my say-so. Zone files include the registry's own signature over each DS record (RRSIG(DS)), and ds-watch archives the signature from before and after the change, plus the day's DNSKEY set needed to verify it. That means an event is a registry-signed statement, checkable independently up to the DNS root, so you don't have to take my word for it. The honest caveat: this proves the record existed within its signature validity window, which dates a change to a window of a few days, not the exact moment, and there's no proof yet for the absence side of a ds_removed event. That needs an NSEC3 denial-of-existence proof, which is on the list but not built.
The numbers so far
The three zones I'm watching — .org, .info, .dev — cover 1,013,221 signed delegations as of the initial baseline on July 4th: 652,985 in .org, 257,170 in .info, 103,066 in .dev. .dev is the one that surprises me: it's a much younger, smaller TLD than the other two, and it still shows over a hundred thousand signed delegations. I don't have a reliable total-domain count per zone to turn that into a clean adoption percentage — the zone files don't carry that number directly — but it's consistent with what I'd expect from a registry that defaults new registrations toward DNSSEC rather than leaving it opt-in.
Algorithm split across all three, by DS record: RSA/SHA-256 at 49.6%, ECDSA P-256 at 46.7%, Ed25519 at 2.5%. A migration sitting almost exactly at its midpoint.
The system went live on its own VPS on July 7th — daily systemd timer, Caddy in front, hardened, key-only SSH. The first production run against that baseline already logged roughly 9,000 real DS change events across the three zones — actual rollovers and key changes from the live zones. Whether that number is normal churn or something worth a closer look needs a few months of daily runs to answer honestly, which is the point of running an observatory instead of writing a one-off scan.
What's missing
ds-watch today is a single-operator observatory with a signed git history, not a transparency log in the CT sense. A real log needs a Merkle tree and independent witnesses; Sigsum is the design I'd build on rather than inventing my own. Also missing: a self-service watchlist, so any domain owner can ask to be mailed the moment their own DS record changes — right now that list is a handful of hardcoded domains, mine included.
None of that changes why it's worth doing now. If a few months of data show the trust chain is boring and observable in practice, it takes away the standard objection to DANE and SMIMEA — that you'd be anchoring identity on a chain nobody watches. The next step outside the code is a problem-statement Internet-Draft for dnsop, on DNSSEC transparency specifically — written once there's enough operational experience to make that case with numbers instead of argument.
Data feeds are open, no keys required: ds-watch.felixmertins.dev/#data. There's also a plain-language explainer if RRSIGs and DS records aren't already part of your vocabulary.