DNS CAA Records: The Underused Security Feature That Controls Who Can Issue Certificates for Your Domain

I discovered CAA records the hard way — reading about a case where a CA mistakenly issued a certificate for a domain they weren’t supposed to. After that, I started adding CAA records to every domain I manage. It takes five minutes and it’s one of those quiet security improvements that nobody notices until something would have gone wrong.

What CAA Records Actually Do

A CAA (Certification Authority Authorization) DNS record specifies which Certificate Authorities are allowed to issue certificates for your domain. If a CA receives a certificate request for your domain and your DNS has a CAA record that doesn’t list that CA, they must refuse to issue the cert.

This isn’t browser enforcement — it’s CA enforcement. The CA checks your DNS before issuing, not the browser when connecting. But since every major CA is required by the CA/Browser Forum to honor CAA records, it’s a meaningful control.

The Basic Syntax

A CAA record has three parts: a flag, a tag, and a value.

example.com.  3600  IN  CAA  0 issue "letsencrypt.org"
  • 0 is the flag — 0 means non-critical (the CA may issue even if they don’t understand the tag), 128 means critical (CA must refuse if they don’t understand the tag). I always use 0 in practice.
  • issue is the tag — more on the different tags below.
  • "letsencrypt.org" is the value — the CA’s domain.

The Three Tags

issue

Controls which CAs can issue regular (single-domain and multi-domain) certificates:

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

If you have multiple CAs you want to allow, add multiple records:

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

If you add even one issue record, any CA not in the list is blocked. If you have no CAA records at all, any CA can issue — it’s the absence of records that permits everything.

issuewild

Controls which CAs can issue wildcard certificates (*.example.com). This is separate from issue:

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

In this example, Let’s Encrypt can issue for specific subdomains, but only DigiCert can issue wildcards. Let’s Encrypt does support wildcard certificates (via DNS challenge), so if you want to allow that:

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

Note: issue does NOT automatically authorize wildcards. You need a separate issuewild record for that.

iodef

This one is for incident reporting. If a CA receives a request that violates your CAA policy, they can notify you:

example.com.  IN  CAA  0 iodef "mailto:security@example.com"
example.com.  IN  CAA  0 iodef "https://example.com/caa-report"

In theory this is useful. In practice, most CAs just refuse the request silently and don’t actually send the iodef notification. I add it anyway because some CAs do honor it, and zero cost to add.

Setting Up CAA Records in Practice

Cloudflare

Cloudflare has a specific CAA record type in their DNS editor. You pick the tag from a dropdown and enter the CA domain. Straightforward.

Route 53

In AWS Route 53, CAA records are supported. The value format is the same: 0 issue "letsencrypt.org" — all three parts as a single string.

Generic DNS / BIND

In a BIND zone file:

@    IN  CAA  0 issue "letsencrypt.org"
@    IN  CAA  0 issuewild "letsencrypt.org"
@    IN  CAA  0 iodef "mailto:admin@example.com"

The @ refers to the zone apex (your root domain). Subdomains inherit the parent’s CAA records unless they have their own.

Inheritance and Subdomain Behavior

This is the part that confused me at first. CAA records are inherited up the DNS tree, but not down.

If you have a CAA record on example.com, then subdomain.example.com also falls under that policy — unless subdomain.example.com has its own CAA records.

So if you set:

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

Then app.example.com, mail.example.com, api.example.com are all covered. You don’t need to add CAA records to every subdomain.

But if you want app.example.com to be able to use a different CA:

app.example.com.     IN  CAA  0 issue "digicert.com"

Now app.example.com has its own policy that overrides the parent. This is useful when different teams manage different subdomains and use different certificate providers.

Blocking All Certificate Issuance

You can explicitly block all certificate issuance for a domain or subdomain:

internal.example.com.  IN  CAA  0 issue ";"

The semicolon in the value is specified by RFC 8659 to mean “no CA is authorized.” This is useful for internal hostnames that should never have public TLS certificates.

Verifying Your CAA Records

After setting up, always verify:

dig CAA example.com

Or with host:

host -t CAA example.com

Or using an online tool like crtmgr.com which can check your certificate and associated DNS records together.

You should see output like:

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

What Happens When a CA Checks and Finds a Violation?

The CA is required to refuse issuance. From the attacker’s perspective: if someone compromises your DNS provider account and tries to get a fraudulent certificate from an unauthorized CA, the CA will check your CAA records and refuse.

Is this foolproof? No. An attacker who can modify your DNS can also remove your CAA records. But it adds a layer of friction and logging. For supply chain attacks and compromised CA scenarios, it provides real protection.

My Typical CAA Setup

For a domain where I use Let’s Encrypt for everything:

example.com.  IN  CAA  0 issue "letsencrypt.org"
example.com.  IN  CAA  0 issuewild "letsencrypt.org"
example.com.  IN  CAA  0 iodef "mailto:admin@example.com"

For a domain where I use both Let’s Encrypt for automation and Sectigo for some paid certs:

example.com.  IN  CAA  0 issue "letsencrypt.org"
example.com.  IN  CAA  0 issue "sectigo.com"
example.com.  IN  CAA  0 issuewild "sectigo.com"
example.com.  IN  CAA  0 iodef "mailto:admin@example.com"

Common Mistakes

Forgetting issuewild when you need wildcard certs. I’ve done this — I had issue "letsencrypt.org" set but no issuewild, then tried to get a wildcard and the CA rejected it. The fix is trivial but the error message from some CAs isn’t always clear.

Setting CAA records before you actually have a certificate. If you add a CAA record restricting to Let’s Encrypt and you already have a cert from another CA, your existing cert isn’t affected — CAA only controls new issuance. But when renewal time comes, the other CA will be blocked.

Not including the CA for internal automation. If you use cert-manager in Kubernetes or some ACME client that uses a specific intermediate or ACME endpoint, make sure the root CA’s domain is in your CAA records. Let’s Encrypt is letsencrypt.org; ZeroSSL is zerossl.com; Sectigo is sectigo.com.


CAA records are a small DNS change that takes almost no effort to implement and gives you meaningful control over certificate issuance for your domain. After setting them up once, you don’t have to think about them again. It’s one of those quiet infrastructure improvements that just keeps working in the background.

Scroll to Top