CAA Records & Certificate Automation

A CAA record set is the only DNS-level control you have over which certificate authorities are permitted to sign for your names, and it is checked by the CA at issuance time — never by a browser — which makes it an operational control on your automation pipeline rather than a runtime security feature.

Certification Authority Authorization is defined by RFC 8659, which replaced the original RFC 6844. The record itself is trivially small: a flags octet, a property tag, and a value string. Everything interesting lives in the lookup algorithm the CA runs before it signs, in the precedence rules between issue and issuewild, and in the way the RFC 8657 parameters bind issuance to a specific ACME account and a specific challenge type. Get those wrong and you either lock yourself out of renewals at 3 a.m. or publish a record that looks restrictive and enforces nothing.

Key implementation points:

  • CAA is evaluated by climbing the DNS tree from the requested name upward, stopping at the first label that holds a CAA RRset — records are never merged across labels.
  • issue, issuewild, iodef and issuemail govern different issuance classes, and issuewild completely displaces issue for wildcard orders.
  • The accounturi and validationmethods parameters from RFC 8657 pin issuance to one ACME account and one challenge type, and they fail closed on CAs that do not understand them.
  • CA-side caching means a CAA change can take up to eight hours to become fully effective regardless of how low you set the record’s TTL.

How a CA resolves the relevant CAA record set

Before signing, the CA computes what RFC 8659 calls the relevant CAA record set for every identifier in the order. The algorithm is a simple upward walk. Ask for CAA at the exact name. If the answer is empty, strip the leftmost label and ask again. Repeat until an RRset is found or the root is reached. The first non-empty RRset encountered is the entire policy; ancestors above it are never consulted, and records at different labels are never combined.

RelevantCAASet(domain):
    while domain is not ".":
        if CAA(domain) is not empty:
            return CAA(domain)
        domain = Parent(domain)
    return empty

Two consequences fall out of this immediately. First, an empty result all the way to the root means unrestricted — any publicly trusted CA may issue. CAA is opt-in; silence is permission. Second, publishing a CAA RRset on a subdomain is not an addition to the apex policy, it is a complete replacement of it. If shop.example.com carries a single issue "sectigo.com" record, the apex’s carefully curated list of four issuers stops applying to that name and everything below it.

Tree-climbing CAA lookup A certificate authority queries CAA at the exact name, gets an empty answer, strips one label at a time, and stops at the first label that carries a CAA record set. RelevantCAASet(www.eu.example.com) www.eu.example.com CAA query returns NODATA eu.example.com CAA query returns NODATA example.com CAA RRset present . (root zone) never queried climb stops Step 1 — exact name aliases followed by the resolver Step 2 — strip one label ask the parent, then its parent Step 3 — first RRset wins this set alone governs issuance Empty all the way up any public CA may issue A CAA RRset at any label overrides every ancestor — the sets are never merged

Aliases complicate the walk in a way that trips people up regularly. A CAA query is an ordinary DNS query, so if the requested name is a CNAME, the resolver follows the alias and the answer comes from the target’s zone, not from the aliased name’s own parent. When www.example.com is a CNAME to edge.cdn-vendor.net, the CA sees whatever CAA records exist at edge.cdn-vendor.net. If the target has none, implementations differ on whether the climb resumes from the parent of the original name or the parent of the target. Treat that as undefined territory: if you rely on CAA and you use aliasing, understand the mechanics in CNAME Flattening Explained and make sure the policy you intend is reachable from both sides.

Verify the climb yourself with dig. The +short output shows the presentation form directly, and an empty response tells you the name is inheriting from somewhere above:

dig +short CAA www.eu.example.com
dig +short CAA eu.example.com
dig +short CAA example.com

0 issue "letsencrypt.org"
0 issuewild "letsencrypt.org"
0 iodef "mailto:[email protected]"

The first two queries return nothing; the third returns the RRset that will actually govern issuance for all three names.

Record structure, property tags and parameters

On the wire a CAA record is RR type 257. Its RDATA is a one-octet flags field, a one-octet tag length, the tag itself as US-ASCII, and then the value — which occupies the rest of the RDATA and carries no length prefix of its own. Only one flag bit is defined: the high bit, value 128, is issuer critical. When it is set and the CA does not recognize the property tag, the CA must refuse to issue rather than ignore the record. With flags 0, an unrecognized tag is simply skipped.

CAA RDATA layout The four fields of CAA record data — flags, tag length, tag and value — shown above the equivalent presentation form and the RFC 3597 generic encoding. CAA RDATA on the wire (RR type 257) flags 1 octet 0 or 128 critical tag length 1 octet 5 for issue property tag US-ASCII issue, issuewild value rest of the RDATA no length prefix Presentation form — every modern authoritative server example.com. 3600 IN CAA 0 issue "letsencrypt.org" RFC 3597 generic form — servers that predate CAA support example.com. 3600 IN TYPE257 \# 22 000569737375656c657473656e63727970742e6f7267

Four property tags matter in practice.

issue names an issuer domain permitted to sign ordinary certificates for the name. The value "letsencrypt.org" permits Let’s Encrypt; the special value ";" permits nobody. Multiple issue records are additive within the same RRset — that is the one place CAA does combine, because they all live at the same label.

issuewild does the same job for wildcard certificates, and its presence changes the meaning of issue. If the relevant set contains at least one issuewild property, issue is ignored entirely when processing a wildcard order. That is the single most misunderstood rule in the specification. A set containing issue "letsencrypt.org" and issuewild ";" allows Let’s Encrypt to sign app.example.com but forbids every CA, including Let’s Encrypt, from signing *.example.com.

iodef carries a URL — normally a mailto: address, sometimes an HTTPS endpoint — where a CA may report a policy violation. Reporting is discretionary; several major CAs do not send iodef notifications at all, so treat it as a useful hint to a human auditor rather than a monitoring channel you can depend on.

issuemail, added by RFC 9495, governs S/MIME certificate issuance. It is deliberately independent: issue and issuewild say nothing about email certificates, so a zone that restricts TLS issuance tightly still permits any CA to sign S/MIME certificates for its addresses until an issuemail property appears.

RFC 8657 layers two parameters onto the issue and issuewild values, appended after the issuer domain and separated by semicolons:

example.com.  300  IN  CAA  0 issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234567; validationmethods=dns-01"
example.com.  300  IN  CAA  0 issuewild "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234567; validationmethods=dns-01"
example.com.  300  IN  CAA  0 iodef "mailto:[email protected]"

accounturi pins issuance to one specific ACME account key. Even if an attacker demonstrates control of your web server, they cannot obtain a certificate unless they are ordering from that exact account. validationmethods restricts which ACME challenge types are acceptable, as a comma-separated list drawn from http-01, dns-01 and tls-alpn-01.

Both parameters fail closed by design. RFC 8659 requires a CA that encounters a parameter it does not understand in an otherwise matching issue property to decline issuance. That is the behavior you want — an unaware CA refuses rather than silently ignoring your restriction — but it also means adding accounturi to a multi-CA policy will quietly disable the CAs that have not implemented RFC 8657. Add parameters per issuer, not blanket-wide.

CAA and automated ACME issuance

Automation is where CAA earns its place. An ACME client running unattended will happily request a certificate whenever it thinks one is due; the CAA record is what constrains the blast radius when the client, the account key, or the web server is compromised. Understanding when the check happens matters as much as what it contains.

A CA performs the CAA lookup while validating an authorization, and again at finalization if the authorization has aged past the reuse window. It does not check CAA when a certificate is presented to a browser, and it does not re-check for certificates already issued. Tightening a CAA policy therefore has no effect on live certificates — it only prevents the next issuance.

Where CAA is checked during an ACME order An ACME order moves from newOrder through authorization and a CAA check to issuance, with the three challenge types below and the validationmethods parameter gating which of them may be used. newOrder client posts names Authorization challenge selected CAA check at validation time Issued cert returned rechecked at finalize if the authorization is older than 8 hours http-01 port 80, well-known path cannot do wildcards dns-01 TXT at _acme-challenge required for wildcards tls-alpn-01 port 443, acme-tls/1 cannot do wildcards validationmethods=dns-01 inside the issue value rejects http-01 and tls-alpn-01 orders for every name this RRset governs

The three challenge types have different exposure profiles, and validationmethods lets you choose deliberately instead of leaving all three open. HTTP-01 proves control by serving a token under /.well-known/acme-challenge/ on port 80; it follows redirects, which means anyone who can hijack a redirect chain or an unclaimed virtual host can pass it. TLS-ALPN-01 negotiates the acme-tls/1 protocol on port 443 and presents a self-signed certificate carrying the challenge in an extension, so it needs privileged control of the TLS terminator rather than just a path. DNS-01 publishes a TXT record at _acme-challenge.<name> and is the only method that can validate a wildcard identifier; the mechanics of driving it from a provider API are covered in Automating ACME DNS-01 Challenges for Wildcard Certificates.

If your issuance is entirely automated through DNS, restricting to validationmethods=dns-01 removes an entire class of attack: a compromised web server no longer yields a certificate. The trade-off is that any fallback path you had — a manual HTTP-01 order during an outage, a vendor that provisions certificates by serving a token — stops working, and the error surfaces as a CAA rejection rather than something obviously related to the change you made.

Provider-specific implementation

Cloudflare

Cloudflare models CAA as a structured record: the API takes a data object with flags, tag and value rather than a flat content string. The dashboard’s CAA helper builds the same payload.

curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CAA",
    "name": "example.com",
    "ttl": 3600,
    "data": { "flags": 0, "tag": "issue", "value": "letsencrypt.org" }
  }'

The operational catch on Cloudflare is Universal SSL. If the zone is proxied, Cloudflare orders certificates on your behalf from its own set of issuers, so your CAA policy must include those issuer domains or edge certificates will fail to renew. At minimum that means letsencrypt.org, pki.goog and ssl.com alongside whatever CAs you use directly — check the dashboard’s CAA helper for the current list before you publish, because it changes as Cloudflare rotates issuers.

resource "cloudflare_record" "caa_apex_le" {
  zone_id = var.zone_id
  name    = "@"
  type    = "CAA"
  ttl     = 3600

  data {
    flags = "0"
    tag   = "issue"
    value = "letsencrypt.org"
  }
}

resource "cloudflare_record" "caa_apex_iodef" {
  zone_id = var.zone_id
  name    = "@"
  type    = "CAA"
  ttl     = 3600

  data {
    flags = "0"
    tag   = "iodef"
    value = "mailto:[email protected]"
  }
}

AWS Route 53

Route 53 stores CAA as the presentation-form string, quotes and all, which means the value field contains embedded double quotes you must escape in JSON. Every record in the RRset goes into one ResourceRecords array — Route 53 replaces the whole set on UPSERT, so omitting an existing record deletes it.

{
  "Comment": "CAA policy for example.com",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "CAA",
        "TTL": 3600,
        "ResourceRecords": [
          { "Value": "0 issue \"amazon.com\"" },
          { "Value": "0 issue \"letsencrypt.org\"" },
          { "Value": "0 issuewild \"amazon.com\"" },
          { "Value": "0 iodef \"mailto:[email protected]\"" }
        ]
      }
    }
  ]
}
aws route53 change-resource-record-sets \
  --hosted-zone-id "$HOSTED_ZONE_ID" \
  --change-batch file://caa-change.json

If you use AWS Certificate Manager, amazon.com alone is not always sufficient — ACM issues from several roots, and AWS documents amazon.com, amazontrust.com, awstrust.com and amazonaws.com as the issuer domains to allow. Include all four unless you have verified which one your certificates actually come from.

resource "aws_route53_record" "caa_apex" {
  zone_id = var.hosted_zone_id
  name    = "example.com"
  type    = "CAA"
  ttl     = 3600

  records = [
    "0 issue \"amazon.com\"",
    "0 issue \"letsencrypt.org\"",
    "0 issuewild \"amazon.com\"",
    "0 iodef \"mailto:[email protected]\"",
  ]
}

GCP Cloud DNS

Cloud DNS also takes presentation-form strings, and gcloud needs careful shell quoting because the value contains double quotes. Use single quotes around each rrdatas element.

gcloud dns record-sets create example.com. \
  --zone="example-zone" \
  --type="CAA" \
  --ttl=3600 \
  --rrdatas='0 issue "pki.goog"','0 issuewild "pki.goog"','0 iodef "mailto:[email protected]"'
resource "google_dns_record_set" "caa_apex" {
  name         = "example.com."
  managed_zone = google_dns_managed_zone.primary.name
  type         = "CAA"
  ttl          = 3600

  rrdatas = [
    "0 issue \"pki.goog\"",
    "0 issuewild \"pki.goog\"",
    "0 iodef \"mailto:[email protected]\"",
  ]
}

Google-managed certificates on Google Cloud load balancers are issued by Google Trust Services, whose issuer domain is pki.goog. Omit it and managed certificate provisioning stalls in a FAILED_CAA_CHECKED state rather than producing a clear error at the point of the DNS change.

BIND and self-hosted zone files

BIND has supported CAA natively since 9.9.6 / 9.10.1B. The presentation form is straightforward, and named-checkzone will reject a malformed value before you reload:

$TTL 3600
example.com.        IN  SOA  ns1.example.com. hostmaster.example.com. (
                              2026072801 ; serial
                              7200 3600 1209600 300 )
example.com.        IN  NS   ns1.example.com.
example.com.        IN  NS   ns2.example.com.
example.com.        IN  CAA  0 issue "letsencrypt.org"
example.com.        IN  CAA  0 issuewild "letsencrypt.org"
example.com.        IN  CAA  0 iodef "mailto:[email protected]"
shop.example.com.   IN  CAA  0 issue "sectigo.com"
shop.example.com.   IN  CAA  0 issuewild ";"

Some hidden-primary setups, appliance DNS, or older secondaries still cannot parse the CAA mnemonic. For those, RFC 3597 defines a generic escape: TYPE257 followed by \#, the RDATA length in octets, and the RDATA as hexadecimal. Assemble it as flags, tag length, tag, value — for 0 issue "letsencrypt.org" that is 00, 05, 6973737565, then the 15 octets of letsencrypt.org, totalling 22:

example.com.  3600  IN  TYPE257  \# 22 000569737375656c657473656e63727970742e6f7267

The two forms are byte-identical on the wire. Always confirm with named-checkzone and a dig against the reloaded server, because a miscounted length silently produces a record that parses but decodes to garbage.

named-checkzone example.com /var/named/example.com.zone
rndc reload example.com
dig @localhost +short CAA example.com

Platform comparison

“Failover support” below reads as what happens when the record is missing, unreachable, or malformed — the behavior that decides whether your policy fails open or closed.

Provider Mechanism Wire behavior Failover support
Cloudflare Structured data object (flags/tag/value); dashboard CAA helper Emits standard type 257; TTL forced to auto (300s) on proxied zones unless set explicitly Missing RRset means unrestricted issuance; a policy that omits Cloudflare’s issuers silently blocks Universal SSL renewal
AWS Route 53 Presentation-form strings in ResourceRecords, quotes escaped Standard type 257; whole RRset replaced on every UPSERT Missing RRset is unrestricted; dropping a record from the array deletes it, so partial updates silently widen policy
GCP Cloud DNS Presentation-form strings in rrdatas; whole RRset replaced per transaction Standard type 257; validated server-side, malformed values rejected at write time Missing RRset is unrestricted; ACM-equivalent managed certs stall in a CAA-failed state rather than erroring at write
BIND / self-hosted CAA mnemonic in the zone file, or TYPE257 \# generic form Byte-identical either way; secondaries transfer it as opaque RDATA Zone load fails outright on a syntax error, so a bad record blocks the reload instead of publishing; miscounted generic length publishes garbage
Azure DNS Record set with typed flags/tag/value fields per record Standard type 257; portal validates tag names against the known set Missing RRset is unrestricted; unknown tags are rejected at write time rather than published with the critical bit

Across every provider the same asymmetry holds: a missing CAA record set never blocks anything, while a present but wrong one blocks everything. That makes CAA a configuration you should verify positively rather than assume, which is the whole argument for managing it alongside the rest of your zone as code — the workflow in Managing DNS Zones as Code with Terraform applies directly.

Deploying a CAA policy step by step

  1. Inventory the issuers actually in use. Enumerate every certificate currently serving traffic and record its issuer. echo | openssl s_client -connect host:443 -servername host 2>/dev/null | openssl x509 -noout -issuer on each hostname is tedious but authoritative. Include internal load balancers, mail gateways, and anything a SaaS vendor provisions on a CNAME’d subdomain.
  2. Map issuer organizations to CAA issuer domains. The CAA value is a domain the CA publishes for this purpose, not the organization’s website — Let’s Encrypt is letsencrypt.org, Google Trust Services is pki.goog, Sectigo is sectigo.com, DigiCert is digicert.com. Getting this wrong produces a record that is syntactically perfect and semantically empty.
  3. Publish the permissive set first. Create the apex RRset containing every issuer from step 2, plus issuewild entries for the CAs that sign wildcards, plus one iodef record. Do not add parameters yet.
  4. Wait out the CA cache window. Give it a full eight hours before drawing conclusions about whether renewals still work.
  5. Force a renewal per issuance path. Run a dry-run or staging order through each ACME client and each managed-certificate integration. This is the step that catches the CA nobody remembered.
  6. Tighten. Remove issuers that produced no orders, then add accounturi and validationmethods to the entries that remain — one issuer at a time, verifying after each.
  7. Add subdomain overrides last. Only after the apex policy is proven should you publish narrower RRsets on subdomains, because each override silently detaches that branch from the apex policy.

The publishing mechanics and verification commands for steps 3 through 6 are worked through end to end in Publishing CAA Records to Restrict Certificate Issuance.

TTL, caching and propagation implications

CAA has an unusual caching profile because two independent caches sit between your zone edit and an issuance decision. The first is the ordinary resolver cache governed by the record’s TTL, which behaves exactly like any other record type — the same reasoning in Mastering TTL Strategies applies. The second is the CA’s own permission cache. The CA/Browser Forum Baseline Requirements permit a CA to treat a CAA check as valid for up to eight hours before issuance, so a CA that checked your policy at 09:00 may issue against that result until 17:00 even if you changed the record at 09:05.

CAA propagation and CA cache window A timeline showing the zone edit, the resolver TTL expiry, and the eight-hour ceiling on a certificate authority's cached CAA result, with guidance on rollout order. From zone edit to enforced CAA policy t = 0 zone edit authoritative updated t + TTL resolver caches expire t + 8 hours CA result guaranteed stale time Lowering the CAA TTL shortens resolver caching only it does not shorten the CA's own eight-hour reuse window Safe rollout order publish the permissive set, wait eight hours, prove renewal, then tighten one entry at a time Certificates already issued are unaffected — CAA is an issuance-time check only

The asymmetry that follows is worth internalizing. Widening a policy is slow: you add an issuer, and the CA may not see it for eight hours, so an urgent certificate order can still fail well after your DNS change has propagated everywhere. Narrowing a policy is also slow in the same direction — the CA may keep issuing under the old, broader policy for the rest of the window. Neither direction is instant, and no TTL value changes that. Plan a CAA edit as an eight-hour operation, not a five-minute one.

A TTL of 300 to 3600 seconds is the sensible range. Going below 300 buys nothing, because the CA cache dominates, and it increases query volume on a record that is queried by CAs and scanners rather than by users. Going above 3600 makes an emergency widening painful without any compensating benefit.

DNSSEC and lookup failure handling

CAA is only as trustworthy as the DNS answer carrying it, and an unsigned zone offers an on-path attacker a straightforward path: strip the CAA response, and the CA sees an empty set, which means unrestricted. The Baseline Requirements address this by allowing a CA to treat a lookup failure as permission to issue only when the failure is outside the CA’s own infrastructure, the lookup has been retried, and the domain has no DNSSEC validation chain to the ICANN root.

That last condition is the operative one. Sign the zone and CAA becomes fail-closed: a DNSSEC validation failure or a forged empty answer stops issuance instead of quietly permitting it. Leave it unsigned and CAA is advisory against a determined attacker. If you are deploying CAA as a security control rather than a documentation exercise, pair it with the signing and rollover practices in DNSSEC Operational Management.

Confirm the CAA answer validates, not merely that it exists:

dig +dnssec +multi CAA example.com @1.1.1.1

Look for the ad flag in the response header. Its absence on a signed zone means the resolver did not validate, and you should investigate before assuming your policy is enforceable:

;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

Also compare a validating answer against one with validation disabled. If +cd returns a record that the validating query does not, the signatures are broken and the CA will see a failure rather than your policy:

dig +short CAA example.com @1.1.1.1
dig +short +cd CAA example.com @1.1.1.1

Troubleshooting and rollback protocol

Symptom Diagnosis Fix
ACME order fails with a caa error naming one identifier dig +short CAA <name> and then each parent label, to find which RRset actually governs Add the CA’s issuer domain to that RRset, or remove the override so the name inherits the apex policy
Only wildcard orders fail; specific names renew fine Check whether an issuewild property exists in the governing set Add issuewild "<ca>" for every CA permitted to sign wildcards; issue alone is ignored once any issuewild is present
Every CA rejects, including ones listed in the record Inspect the value for a parameter — accounturi or validationmethods — that the CA may not implement Split the entry: keep a parameterless issue for CAs without RFC 8657 support, parameters only on those that have it
Managed certificate renewal stalls with no error in DNS The platform CA is not in the RRset; the failure surfaces in the certificate resource, not the zone Add the platform issuer domain (pki.goog, amazon.com, Cloudflare’s set) and re-trigger provisioning
Record present but the CA reports an empty set The name is a CNAME, so the CAA query resolved at the alias target Publish the policy at the alias target’s zone, or move the record to a name that is not aliased
Policy edit made no difference after 20 minutes Both resolver TTL and the CA’s eight-hour window are in play Confirm authoritative answers changed with dig @ns1, then wait out the full window before retrying

Rollback is deliberately simple, because a broken CAA policy is an availability problem and you want the fastest possible path back to issuance:

  1. Restore the permissive apex RRset from version control. If you do not have one, publish 0 issue "<the CA you need right now>" plus 0 issuewild "<same>" immediately.
  2. Delete any subdomain CAA RRsets you added in the failed change. Removing them restores inheritance from the apex, which is almost always the safer state.
  3. Verify authoritatively before waiting: dig @ns1.example.com +short CAA example.com must show the restored set.
  4. Retry the failing order. If it still fails, the CA is inside its cache window — wait, do not keep editing the zone, because each edit resets your ability to reason about what the CA last saw.
  5. Only once issuance is confirmed healthy should you re-attempt the tightening, one record at a time.

Edge cases and gotchas

  • A wildcard order strips the * label before the climb. For *.example.com the CA evaluates the policy at example.com and upward. Publishing a CAA RRset at the literal *.example.com node accomplishes nothing at all.
  • You cannot put CAA on a name that is a CNAME. DNS forbids other data alongside a CNAME, so the record has to live at the alias target or at a non-aliased name.
  • Delegation does not escape the parent. If ops.example.com is delegated to a child zone with no CAA records anywhere in it, the climb continues into the parent zone and the apex policy applies to the whole delegated branch.
  • The _acme-challenge name’s own CAA is irrelevant. CAA is evaluated against the certificate’s identifiers, not against the challenge record’s name, so delegating _acme-challenge with a CNAME to a dedicated validation zone does not change which CAs may issue.
  • issue ";" and an absent record are opposites. The empty value forbids everyone; an absent RRset permits everyone. A typo that deletes the record has the exact inverse of the intended effect.
  • Semicolons inside the value need care in zone files. In BIND, ; starts a comment outside a quoted string. 0 issue ";" is fine because it is quoted; 0 issue ; is a syntax error that may or may not be caught depending on the tooling.
  • The critical flag applies per record, not per set. Setting 128 on your iodef entry while leaving issue at 0 means CAs that do not implement iodef reporting must refuse to issue — a self-inflicted outage that looks inexplicable from the DNS side.
  • Certificate transparency is not a substitute. CAA prevents issuance; CT logs tell you after the fact that it happened. Monitor both, and treat an unexpected CT entry for a name with a tight CAA policy as a serious incident.
  • S/MIME is a separate policy. Without an issuemail property, your TLS restrictions place no constraint on email certificate issuance for the same domain.
  • CAA records are ordinary records for zone operations. They transfer, sign, and version like anything else — see Understanding DNS Record Types for how type 257 sits alongside the rest of the zone.

Frequently Asked Questions

Does adding a CAA record revoke certificates that were already issued? No. CAA is consulted only at issuance time, so existing certificates remain valid until they expire and browsers never look at the record. Tightening a policy prevents the next order from succeeding; it does nothing to certificates already in the wild, which is why you also need certificate transparency monitoring.

If I publish CAA on a subdomain, does the apex policy still apply to it? No, and this is the most common misreading of the specification. The CA stops climbing at the first label with any CAA RRset, so a subdomain record replaces the apex policy for that name and everything under it rather than adding to it. Repeat every issuer you still need in the subdomain’s own set.

Why do my wildcard orders fail when issue clearly lists the CA? Because the relevant record set contains at least one issuewild property, which causes issue to be ignored entirely for wildcard identifiers. Add an explicit issuewild "<ca>" for every CA that should be allowed to sign wildcards, or remove the issuewild records so issue governs both classes again.

How long should I wait after a CAA change before trusting it? Eight hours. The Baseline Requirements let a CA reuse a CAA check result for up to that long before issuance, and no TTL setting on your side shortens it. Plan CAA edits as an eight-hour change window and verify with a real issuance attempt at the end rather than assuming DNS propagation was sufficient.

Back to DNS Fundamentals & Advanced Record Configuration