ServerRecords

CAA Records: Deciding Which Certificate Authorities Can Speak for Your Domain

A practical guide to DNS CAA records - the issue, issuewild and iodef tags, the critical flag, how CAs climb the domain tree, and how to check yours.

caadnssslcertificatespkisecurity

Every padlock in a browser rests on one assumption: that the certificate behind it was issued by an authority the browser trusts, for the domain it actually covers. For years there was a hole in that logic. Any publicly trusted Certificate Authority - Let's Encrypt, DigiCert, Sectigo, whoever - could issue a certificate for any domain on the internet. Your domain included. You never got a say.

That sounds abstract until a CA gets breached. In 2011, attackers who compromised the Dutch CA DigiNotar minted hundreds of fraudulent certificates, including ones for Google, and used them to intercept traffic that looked perfectly valid to the victims' browsers. The "trust anyone" model had failed in exactly the way people had warned it could.

CAA records are the fix. A CAA (Certification Authority Authorization) record is a DNS entry where you name the CAs allowed to issue certificates for your domain - and, by implication, forbid the rest. If you want to see what a domain currently declares, the CAA record lookup fetches its CAA records and translates the tags and flags into plain language. Before we get to reading one, it helps to know what the pieces mean.

How the enforcement actually happens

CAA lives in DNS as record type 257, and its power comes from a rule the CAs agreed to, not from anything your DNS server does. Since 8 September 2017, the CA/Browser Forum has required every public CA to check CAA before issuing. The flow is simple: a CA receives a request for a certificate, looks up the domain's CAA records, and if a record exists that doesn't list them, they must refuse.

The catch worth internalising: if you publish no CAA record at all, every CA is permitted. Absence means "anyone may issue." So the record isn't just a restriction you bolt on later - publishing one at all is what turns the protection on.

Anatomy of a record

A single CAA entry looks like this:

example.com.  IN  CAA  0 issue "letsencrypt.org"

Three parts do the work: a flag, a tag, and a value.

The flag is an 8-bit field, and in practice you care about one bit of it - the issuer critical flag.

Flag Meaning
0 Non-critical. A CA that doesn't understand a tag may ignore it and carry on.
128 Critical. A CA that doesn't understand the tag must refuse to issue, full stop.

The tag says what kind of rule this is. There are three you'll meet:

Tag What it does
issue Authorises a CA to issue standard certificates, e.g. 0 issue "digicert.com".
issuewild Governs wildcard certificates like *.example.com, overriding issue for those.
iodef A mailto: or URL address where CAs report attempts to get an unauthorised certificate.

The value is the string in quotes - usually a CA's identifying domain. A couple of patterns are worth memorising because they come up constantly. issue "letsencrypt.org" lets Let's Encrypt issue. issuewild ";" - a bare semicolon - authorises no one for wildcards, which is how you ban wildcard certificates for the domain entirely. And iodef "mailto:[email protected]" routes violation reports to a mailbox you watch.

Why CAs climb the tree

Here's the part that trips people up. Certificates get requested for deep hostnames - imagine app.dev.london.example.com. The CA doesn't just look at that exact name. It climbs the domain hierarchy one label at a time, looking for a CAA record:

app.dev.london.example.com
no CAA record — keep climbing
dev.london.example.com
no CAA record — keep climbing
london.example.com
no CAA record — keep climbing
example.com
CAA found — stop and apply these rules
A CA walks up the domain tree until it finds a CAA record.

The moment it finds a set of CAA records, it stops and those rules apply. This is how you set one policy at the apex of your domain and have it govern everything beneath, while still leaving room to publish stricter rules on a specific subdomain when you need them.

This tree-climbing is how CAA works under the hood - it's the CA's job during issuance, not something you configure per-record. There's a related mechanism too: ACME clients can pin issuance to a specific account with an accounturi parameter, as in issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/123456", so only one Let's Encrypt account can act on the authorisation. Both are good to understand as background; neither is something you'd set and forget without knowing why.

Reading your own record

The lookup fetches whatever CAA records a domain publishes and lays out what they say: which CAs are authorised under issue, whether wildcards are allowed or blocked via issuewild, where iodef reports would go, and whether the critical flag is set. It's a read-and-explain view - useful when you're checking that a policy you published actually landed, or auditing a domain you've inherited and want to understand quickly.

Misconfiguration here has teeth. The classic outage is a renewal failure: an automated ACME client like Certbot tries to renew, but someone tightened the CAA record and left Let's Encrypt off the list. Nothing looks broken in your DNS, yet the certificate quietly fails to renew and eventually expires. Seeing the authorised set spelled out in one place is often how you catch that before it bites.

A scenario worth stealing

Picture a financial firm with a rule: every certificate must be an EV cert from one central DigiCert account. A dev team, moving fast, stands up payments.enterprise.com and runs a script to grab a free Let's Encrypt certificate. With no CAA record, Let's Encrypt happily issues it - and now there's a live, unmonitored certificate on a payments hostname that security has never seen. That's shadow IT with a valid padlock on it.

The fix is two records at the apex:

enterprise.com.  IN  CAA  0 issue "digicert.com"
enterprise.com.  IN  CAA  0 iodef "mailto:[email protected]"

Now when Let's Encrypt checks CAA, it sees only digicert.com authorised, refuses the request, and - because of the iodef line - the security team gets a report about the attempt. The rogue certificate never exists, and someone learns about the shortcut.

Worth doing

Publishing a CAA record is one of the cheapest hardening steps available: a couple of DNS entries that shut the door on any CA you didn't approve. Just remember to include every CA you actually use - the ACME client behind your renewals counts - so you're locking out attackers, not yourself. Check what a domain declares with the CAA record lookup, see it alongside the rest of a domain's DNS with the All DNS Records lookup, and if you're serious about issuance integrity, confirm the records themselves are protected from tampering with a DNSSEC check.