How CAA changes certificate issuance
CAA (RFC 8659) is a whitelist enforced by the CAs themselves. Publish no CAA record and every public CA may issue for your domain — that is the default, and it is not a misconfiguration. Publish one and the set narrows to exactly what you listed. The CA/Browser Forum has made the check mandatory since September 2017, so this is enforced in practice, not merely specified.
dig +noall +answer github.com CAA
github.com. 3600 IN CAA 0 issue "digicert.com"
github.com. 3600 IN CAA 0 issue "sectigo.com"
github.com. 3600 IN CAA 0 issue "globalsign.com"
github.com. 3600 IN CAA 0 issue "letsencrypt.org"
github.com. 3600 IN CAA 0 issuewild "digicert.com"
github.com. 3600 IN CAA 0 issuewild "sectigo.com"
github.com. 3600 IN CAA 0 issuewild "letsencrypt.org"
dig +noall +answer google.com CAA
google.com. 17222 IN CAA 0 issue "pki.goog"| Part | Example | Meaning |
|---|---|---|
| Flags | 0 | The critical bit. 0 is normal. 128 means a CA that does not understand the tag must refuse to issue. |
| issue | 0 issue "letsencrypt.org" | This CA may issue non-wildcard certificates for the domain. |
| issuewild | 0 issuewild "digicert.com" | This CA may issue wildcard certificates. If absent, the issue tag governs wildcards too. |
| iodef | 0 iodef "mailto:[email protected]" | Where a CA should report a policy violation. Optional and advisory. |
| issue ";" | 0 issue ";" | A semicolon as the value forbids all issuance. Use deliberately — it blocks every CA. |
The tree-climbing rule
CAA is the one record type that is effectively inherited, and the mechanism surprises people. When a CA checks shop.example.com, it queries that exact name first. If no CAA record exists, it strips a label and queries example.com, then continues upward until it finds a CAA record set or reaches the root. The first record set found wins outright — parent policies are not merged with child policies.
Read the full explanation of caa record lookup results ↓Show less ↑
The practical consequence: publishing a CAA record on a subdomain completely replaces the apex policy for that subdomain, not adds to it. If example.com authorises Let's Encrypt and DigiCert, and you add 0 issue "letsencrypt.org" at shop.example.com, DigiCert can no longer issue for shop.example.com. Subdomain records must list every CA that subdomain needs.
0 issue "letsencrypt.org" record with no issuewild still permits Let's Encrypt to issue wildcards. But add 0 issuewild "digicert.com" and Let's Encrypt is now blocked from wildcards entirely, because issuewild overrides issue for wildcard requests. Renewals that worked for a year suddenly fail.Choosing what to publish
- Inventory every certificate you currently hold, including ones issued by CDNs, load balancers, and hosting panels on your behalf. The SSL certificate checker shows the issuer of the live certificate for each hostname.
- List every one of those issuers in
issuetags. Missing one breaks renewal months later, when nobody connects the outage to a DNS change. - Add
issuewildonly when you actually want to restrict wildcards differently. Otherwise leave it out and letissuegovern both. - Add an
iodefaddress —mailto:orhttps://— so you learn when someone attempts unauthorised issuance. - Keep the TTL moderate (3600). CAs check at issuance time, so a long TTL delays legitimate policy changes without adding security.
- Re-check here after publishing, and again the first time each certificate renews.
Note which CA names to use. The value is an identifier the CA publishes, not a hostname you choose: letsencrypt.org, digicert.com, sectigo.com, globalsign.com, pki.goog, amazon.com and amazontrust.com for ACM, ssl.com. Get it wrong and the CA simply does not match itself and refuses.
Common failures and fixes
- "CAA record prevents issuance" from your ACME client. The CA you are using is not in the set. Check the exact name it expects — for ACM it is
amazon.com,amazontrust.com,awstrust.com, andamazonaws.com, and omitting any of them can break renewals. - Wildcard issuance fails while single-name certificates work. An
issuewildrecord exists that excludes your CA. Add it, or remove theissuewildrecords entirely. - Certificates fail only for one subdomain. That subdomain has its own CAA set overriding the apex. Remember: nearest record wins, nothing is merged.
- A CDN cannot provision a certificate for your domain. Many CDNs issue on your behalf through their own CA. Authorise it, or the provisioning silently retries forever.
- Record present but ignored. Check the tag spelling —
issuewildhas no space or hyphen — and that the value is quoted. Some panels expect the three parts in separate fields; putting0 issue "letsencrypt.org"into a single value field then produces a malformed record.
Checking CAA from the command line
# The domain's own CAA records
dig +short example.com CAA
# Walk up the tree exactly as a CA does
for n in shop.example.com example.com com; do
echo -n "$n: "; dig +short "$n" CAA | tr '\n' ' '; echo
done
# Confirm which CA issued the certificate you are actually serving
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -issuer -dates