cerf
Slack

Slack

The day DNSSEC took Slack down for 24 hours

A FedRAMP requirement, a Route 53 NSEC edge case, and a cached DS record: the most instructive DNSSEC failure ever written up.

The setup

In September 2021 Slack needed DNSSEC on slack.com to meet FedRAMP Moderate. Their DNS estate was split: Amazon Route 53 held the primary slack.com zone, NS1 served delegated subzones for traffic management, and the domain was registered through MarkMonitor, which is where the DS record would be published into the .com parent zone.

DNSSEC has two halves, and both must agree: the zone signs its records (Route 53 manages the zone-signing key, you hold the key-signing key in KMS), and the parent zone publishes a DS record that anchors your KSK into the global chain of trust. Signing without the DS accomplishes nothing; a DS pointing at a zone that stops signing breaks everything.

SlackSlack's split DNS estate and the two halves of DNSSEC
Slack's split DNS estate and the two halves of DNSSECGlobal DNS hierarchyAWS CloudThird-party providersRoute 53 (slack.com primary zone)requires DNSSECapp.slack.com?walk from rootdelegates .comNS delegationRRSIG validationsigns RRsetsKSK signs DNSKEY setpublishes DS into parentDS covers KSKdelegates subzonesFedRAMPModeratecompliance driverSlack userresolves app.slack.…ValidatingresolverDNSSEC-awareRoot zone (.)top of the chain.com TLD zonepublishes DS, TTL 8…DS recordanchors the KSKMarkMonitordomain registrarslack.comhosted zoneRoute 53 primaryZone-signingkeymanaged by Route 53KMS asymmetrickeyholds the KSKNS1delegated subzones
Trace
A FedRAMP Moderate requirement drives DNSSEC onto slack.com. The estate is split three ways: Route 53 holds the primary zone and signs records (managing the ZSK, with the KSK in KMS), NS1 serves delegated traffic-management subzones, and MarkMonitor publishes the DS into the .com parent. DNSSEC only works when both halves agree: the zone signs, AND the parent anchors the KSK with a DS record.

What broke

Slack's third rollout attempt hit an edge case in how Route 53 answered non-existence proofs for wildcard records. When resolvers asked for a AAAA record under *.slack.com that did not exist, the NSEC response failed to say that A records DID exist. Resolvers doing aggressive NSEC caching (RFC 8198), notably Google Public DNS, cached that answer as 'nothing exists here at all' and stopped resolving slack.com A records entirely.

The rollback made it worse in the most instructive way possible: the team pulled the DS record from the registrar and assumed the change was immediate. But the .com zone had served that DS with a 24-hour TTL, so validating resolvers kept demanding signatures from a zone that had just turned signing off. The result was SERVFAIL for roughly a day for affected users. AWS later fixed the NSEC type-bitmap behavior in Route 53.

SlackTwo failures: the NSEC wildcard bug and the 24-hour rollback trap
Two failures: the NSEC wildcard bug and the 24-hour rollback trapFailure 1 - NSEC aggressive cachingFailure 2 - rollback DS-TTL trapAAAA app.slack.com?query under *.slack.comreturns NSECcached as full non-existencestoresA never re-queriedpulled DS (assumed instant)still serves cached DSdemands RRSIGno signatures producedreturnsAffected usercannot reach slack.…Google PublicDNSRFC 8198 aggressive…Route 53slack.comsigned zoneNSEC prooftype bitmap omits ANegative cacheentry'name has nothing'A recordapp.slack.comMarkMonitorDS removed at regis….com TLD zoneDS still cached, TT…Validatingresolverstill trusts cached…slack.com zonesigning turned OFFSERVFAIL~24 hours for affec…
Trace
The third rollout attempt failed twice over. First, Route 53's NSEC proof for a non-existent AAAA under *.slack.com omitted A from the type bitmap; resolvers doing aggressive NSEC caching (RFC 8198), notably Google Public DNS, cached it as 'nothing exists here' and stopped resolving A records. Then the rollback made it worse: the DS was pulled at the registrar but .com kept serving the cached DS for its 24-hour TTL, so validating resolvers demanded signatures a now-unsigned zone could not produce, returning SERVFAIL for roughly a day.

What this teaches for the exam

Enabling DNSSEC on Route 53 is two steps in a strict order: enable signing on the hosted zone (KSK backed by an asymmetric KMS key), then publish the DS at the parent through your registrar. Disabling is the same walk in reverse with a mandatory wait: remove the DS record, wait out the parent's DS TTL (86400 seconds for .com), and only then disable signing.

Wildcards plus DNSSEC deserve their own test plan, because non-existence proofs (NSEC) behave differently around them, and resolver behavior varies. And when a question mentions per-subdomain DNSSEC or partial rollout, remember Slack's lesson: the chain of trust is zone-wide, and you cannot enable it for only part of a zone.

SlackEnable and disable DNSSEC in strict order (with a mandatory wait)
Enable and disable DNSSEC in strict order (with a mandatory wait)Enable - in orderDisable - reverse, with mandatory waitThe wrong path (what Slack did)KSK in KMSthen, step 2DS publishedDS removed (not instant)TTL must drainthen disableif you skip the waitsigning off, DS cacheddemand signatures -> failStep 1: Enablesigningon the hosted zoneAsymmetric KMSkeybacks the KSKStep 2: PublishDSat MarkMonitor into….com parentzoneDS now presentStep 1: RemoveDSat the registrar.com parentzoneDS cached, TTL 86400Step 2: Waitout DS TTL86400s for .comStep 3: Disablesigningonly after TTL expi…Slack's mistakedisabled signing ea…Validatingresolversstill hold the DSSERVFAIL~24 hours
Trace
Enabling is two ordered steps: sign the zone first (KSK backed by an asymmetric KMS key), then publish the DS at the registrar. Disabling is the same walk in reverse with a mandatory wait: remove the DS, wait out the parent's DS TTL (86400s for .com), and only then disable signing. Slack's mistake was disabling signing before the cached DS expired, which is exactly the path that produces SERVFAIL.

Sources

Practice what you just read

6 questions from this architecture

Loading…