Certificate Authority Authorization (CAA) records are a DNS security mechanism that lets domain owners specify which certificate authorities (CAs) are allowed to issue certificates for their domains. By publishing CAA records, you prevent unauthorized CAs from issuing certificates — reducing the risk of misissued or fraudulent TLS certificates.

This guide covers how to manage CAA records across three major open-source DNS servers: BIND, PowerDNS, and Knot DNS. We’ll explore zone file syntax, automated management patterns, and best practices for enforcing certificate issuance policies.

Understanding CAA Records

CAA records (RFC 8659) define which CAs can issue certificates for a domain and its subdomains. When a CA receives a certificate request, it must check the domain’s CAA records and refuse issuance if it’s not authorized.

CAA record format:

1
2
3
example.com. CAA 0 issue "letsencrypt.org"
example.com. CAA 0 issuewild ";"
example.com. CAA 0 iodef "mailto:security@example.com"

The three CAA properties are:

  • issue — Authorizes a specific CA to issue any certificate type for the domain
  • issuewild — Authorizes a specific CA to issue wildcard certificates only
  • iodef — Specifies where CAs should report policy violations (email or URL endpoint)

The flag byte (0 in the examples) controls behavior: 0 means the CA should process the record normally, while 128 marks the record as critical (CA must reject if it doesn’t understand the property).

Why Self-Host CAA Record Management?

Managing CAA records through your own DNS infrastructure provides:

  • Certificate issuance control — Only your approved CAs can issue certificates, preventing misissuance
  • Compliance enforcement — Meet regulatory requirements for certificate governance and PKI policies
  • Incident response — Receive violation reports via iodef when unauthorized issuance is attempted
  • Subdomain delegation — Set different CAA policies for specific subdomains while maintaining global defaults
  • Cost savings — Prevent accidental certificate issuance from expensive CAs when free alternatives exist
  • Security posture — Reduce attack surface by limiting which CAs can issue certificates for your infrastructure

For organizations running internal PKI, managing multiple domains, or operating in regulated industries, CAA records are a foundational security control that should be actively managed rather than left to default DNS provider settings.

BIND: The Reference DNS Server

BIND (ISC-maintained) is the most widely deployed DNS server and the reference implementation for DNS standards. CAA records are natively supported in BIND 9.10+ (released 2015).

BIND Zone File with CAA Records

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$TTL 86400
@   IN  SOA ns1.example.com. admin.example.com. (
            2026051801  ; Serial
            3600        ; Refresh
            900         ; Retry
            604800      ; Expire
            86400       ; Minimum TTL
)

; Name servers
@       IN  NS  ns1.example.com.
@       IN  NS  ns2.example.com.

; CAA records — primary policy
@       IN  CAA 0 issue "letsencrypt.org"
@       IN  CAA 0 issue "pki.goog"
@       IN  CAA 0 issuewild ";"
@       IN  CAA 0 iodef "mailto:security@example.com"
@       IN  CAA 0 iodef "https://caa-reports.example.com/violations"

; Subdomain-specific CAA policy
api     IN  CAA 0 issue "step-ca.internal"
api     IN  CAA 0 issuewild "step-ca.internal"

; Wildcard CAA for all subdomains
*.app   IN  CAA 0 issue "letsencrypt.org"
*.app   IN  CAA 0 issuewild "letsencrypt.org"

; A/AAAA records
@       IN  A   203.0.113.10
www     IN  A   203.0.113.10
api     IN  A   203.0.113.20

BIND Docker Compose Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
version: "3.8"
services:
  bind9:
    image: ubuntu/bind9:9.18-23.04_edge
    container_name: bind9-caa
    environment:
      - BIND9_USER=root
    ports:
      - "53:53/tcp"
      - "53:53/udp"
    volumes:
      - ./named.conf:/etc/bind/named.conf
      - ./zones/:/etc/bind/zones/
      - ./logs:/var/log/named
    restart: unless-stopped

Verifying CAA Records with BIND

1
2
3
4
5
6
7
8
# Query CAA records
dig example.com CAA @localhost

# Check with dnssec-validation
dig +dnssec example.com CAA @localhost

# Verify zone file syntax
named-checkzone example.com /etc/bind/zones/db.example.com

PowerDNS Authoritative Server

PowerDNS (4,300+ GitHub stars) is a high-performance DNS server with a flexible backend architecture supporting SQL databases, LDAP, and zone files. CAA records are fully supported in PowerDNS 4.0+.

PowerDNS CAA Management via pdnsutil

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Add CAA records via pdnsutil
pdnsutil add-record example.com @ CAA '0 issue "letsencrypt.org"'
pdnsutil add-record example.com @ CAA '0 issue "pki.goog"'
pdnsutil add-record example.com @ CAA '0 issuewild ";"'
pdnsutil add-record example.com @ CAA '0 iodef "mailto:security@example.com"'

# Subdomain-specific CAA
pdnsutil add-record example.com api CAA '0 issue "step-ca.internal"'
pdnsutil add-record example.com api CAA '0 issuewild "step-ca.internal"'

# List all CAA records
pdnsutil list-zone example.com | grep CAA

# Verify zone
pdnsutil check-zone example.com

PowerDNS Docker Compose with PostgreSQL Backend

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
version: "3.8"
services:
  pdns-db:
    image: postgres:16
    container_name: pdns-postgres
    environment:
      POSTGRES_DB: pdns
      POSTGRES_USER: pdns
      POSTGRES_PASSWORD: SecurePdnsPass!
    volumes:
      - pdns-db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U pdns"]
      interval: 5s
      timeout: 3s
      retries: 5

  pdns:
    image: pschiffe/pdns-postgresql:4.9
    container_name: pdns-authoritative
    environment:
      PDNS_gmysql_host: pdns-db
      PDNS_gmysql_dbname: pdns
      PDNS_gmysql_user: pdns
      PDNS_gmysql_password: SecurePdnsPass!
      PDNS_master: "yes"
      PDNS_api: "yes"
      PDNS_api_key: pdns-api-key-here
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "8081:8081"
    depends_on:
      pdns-db:
        condition: service_healthy
    restart: unless-stopped

volumes:
  pdns-db-data:

PowerDNS API for Automated CAA Management

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Add CAA records via REST API
curl -s -X PATCH "http://localhost:8081/api/v1/servers/localhost/zones/example.com" \
  -H "X-API-Key: pdns-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "rrsets": [
      {
        "name": "example.com.",
        "type": "CAA",
        "ttl": 3600,
        "changetype": "REPLACE",
        "records": [
          {"content": "0 issue "letsencrypt.org"", "disabled": false},
          {"content": "0 issue "pki.goog"", "disabled": false},
          {"content": "0 issuewild ";"", "disabled": false},
          {"content": "0 iodef "mailto:security@example.com"", "disabled": false}
        ]
      }
    ]
  }'

Knot DNS: High-Performance Authoritative Server

Knot DNS (300+ GitHub stars) is a high-performance authoritative-only DNS server developed by CZ.NIC. It features automatic DNSSEC signing, zone transfers, and a comprehensive CLI. CAA records are fully supported.

Knot DNS CAA Configuration via zone files

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
; /etc/knot/zones/example.com.zone
$TTL 3600
@       SOA   ns1.example.com. admin.example.com. (
                2026051801  ; Serial
                3600        ; Refresh
                900         ; Retry
                604800      ; Expire
                86400       ; Minimum
              )

@       NS    ns1.example.com.
@       NS    ns2.example.com.

; CAA policy
@       CAA   0 issue "letsencrypt.org"
@       CAA   0 issue "pki.goog"
@       CAA   0 issuewild ";"
@       CAA   0 iodef "mailto:security@example.com"

; Subdomain overrides
api     CAA   0 issue "step-ca.internal"
api     CAA   0 issuewild "step-ca.internal"

; Host records
@       A     203.0.113.10
www     A     203.0.113.10
api     A     203.0.113.20

Knot DNS Docker Compose Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
version: "3.8"
services:
  knot:
    image: cznic/knot:latest
    container_name: knot-dns
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "8081:8081"
    volumes:
      - ./knot.conf:/etc/knot/knot.conf
      - ./zones/:/var/lib/knot/zones/
      - ./keys/:/etc/knot/keys/
    restart: unless-stopped

Knot DNS CLI for CAA Management

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Connect to Knot control socket
knotc zone-begin example.com

# Add CAA records
knotc zone-set example.com example.com. 3600 CAA '0 issue "letsencrypt.org"'
knotc zone-set example.com example.com. 3600 CAA '0 issuewild ";"'
knotc zone-set example.com example.com. 3600 CAA '0 iodef "mailto:security@example.com"'

# Commit changes
knotc zone-commit example.com

# Flush zone to disk
knotc zone-flush example.com

# Verify CAA records
knotc zone-read example.com example.com. CAA

Comparison: BIND vs PowerDNS vs Knot DNS for CAA

FeatureBINDPowerDNSKnot DNS
CAA Support9.10+ (RFC 6844/8659)4.0+2.0+
ConfigurationZone filesSQL/API/Zone filesZone files + CLI
CAA APINone (file-based)Full REST APIknotc CLI
DNSSECNativeNativeNative (auto-sign)
PerformanceGoodExcellentExcellent
SQL BackendNoYes (PostgreSQL/MySQL)No
Zone TransfersAXFR/IXFRAXFR/IXFRAXFR/IXFR
Dynamic UpdatesYesYesLimited
Active DevelopmentYes (ISC)Yes (PowerDNS)Yes (CZ.NIC)
Docker Imagesubuntu/bind9pschiffe/pdns-*cznic/knot
Learning CurveModerateModerateLow-Moderate

CAA Record Best Practices

  1. Always set a default policy — Even if you allow all CAs, explicitly document your policy with CAA 0 issue ";" (allow all) or restrict to specific CAs.

  2. Use iodef for monitoring — Set up an email address or webhook endpoint to receive violation reports. This provides early warning of unauthorized certificate requests.

  3. Restrict wildcard issuance — Use issuewild ";" to block all wildcard certificates, or limit wildcard issuance to specific CAs you trust for this purpose.

  4. Set subdomain-specific policies — Different subdomains may have different certificate requirements. Use specific CAA records for API endpoints, mail servers, and internal services.

  5. Use critical flags sparingly — Setting the critical flag (128) on unknown properties will cause all CAs to reject issuance. Only use it for experimental or proprietary extensions.

  6. Automate CAA management — Use PowerDNS API or Knot DNS CLI to integrate CAA record management into your CI/CD pipeline. Update CAA records when adding or removing approved CAs.

  7. Test CAA enforcement — Use tools like caa-record-validator or test with Let’s Encrypt’s staging environment to verify your CAA records are being respected.

Why Self-Host DNS for CAA?

Running your own authoritative DNS server gives you direct control over CAA records without relying on third-party DNS providers. This is critical for organizations that need to enforce strict certificate issuance policies, comply with regulatory requirements, or manage CAA records across hundreds of domains.

Combined with internal PKI solutions like smallstep certificates or EJBCA, self-hosted DNS CAA management creates a comprehensive certificate governance framework. You control which public CAs can issue certificates and which internal CA handles private infrastructure.

For related DNS infrastructure, see our DNS firewall RPZ guide, PKI certificate management guide, and certificate transparency guide.

FAQ

What happens if a domain has no CAA records?

If no CAA records exist, any CA can issue certificates for that domain. This is the default behavior. Publishing CAA records explicitly restricts which CAs are authorized, so the absence of CAA records means no restrictions apply.

Can CAA records prevent all certificate misissuance?

CAA records are effective against accidental or unauthorized issuance from compliant CAs. However, they don’t prevent issuance from CAs that don’t check CAA records (rare but possible), or from attackers who compromise your DNS and modify CAA records. Always combine CAA with DNSSEC for cryptographic zone integrity.

How often should I review CAA records?

Review CAA records whenever you change certificate providers, add new domains, or modify your PKI policy. Set up automated monitoring to alert when CAA records are changed unexpectedly, using zone transfer monitoring or API audit logs.

Do CAA records affect subdomains?

CAA records are inherited by subdomains unless overridden. If example.com has CAA 0 issue "letsencrypt.org", then api.example.com inherits this policy unless you set a specific CAA record for api.example.com. Use CAA 0 issue ";" at the subdomain level to allow all CAs for that specific subdomain.

What is the difference between issue and issuewild?

issue authorizes a CA to issue any certificate type (single domain, SAN, wildcard). issuewild specifically authorizes wildcard certificate issuance. Setting issuewild ";" blocks all wildcard certificates, while issue "ca.example.com" allows that CA to issue both regular and wildcard certs.

Can I use CAA records for internal/private CAs?

Yes. CAA records can reference any CA identifier, including internal CAs. For example, CAA 0 issue "step-ca.internal" restricts issuance to your internal smallstep CA. External public CAs won’t recognize this identifier and will refuse issuance, effectively restricting certificate creation to your internal PKI.