checker-caa
CAA posture checker for happyDomain.
Validates that certificates observed by checker-tls were issued by a
CA actually authorized by the domain's CAA records. This checker
runs no network probes of its own: it reads the svcs.CAAPolicy
service body (already parsed by happyDomain from the zone's CAA
resource records) and the tls_probes observations published by
checker-tls, and cross-references them via the CCADB "CAA
Identifiers" mapping.
How it works
- The host runs this checker on a
svcs.CAAPolicy service.
Collect unmarshals the service body into a list of
(flag, tag, value) entries. No network.
- The
caa_compliance rule:
- calls
obs.Get("caa_policy", …) to load its own payload;
- calls
obs.GetRelated("tls_probes") to pick up every TLS probe
produced on the target;
- resolves each observed issuer (keyed by
IssuerAKI with an
IssuerDN fallback) against the embedded CCADB CSV to find the
CA's published CAA identifier domain(s);
- compares the observed identifiers against the
issue /
issuewild allow list (or flags a DisallowIssue violation).
Rules
| Code |
Description |
Severity |
caa_compliance |
Cross-references TLS certificates observed on the domain against its CAA issue/issuewild policy, mapping each observed issuer to its CCADB-published CAA identifier. |
CRITICAL |
Rule outcomes
caa_ok: every observed issuer is authorized by the zone's CAA
policy.
caa_no_tls: no TLS probes related to this target have been
published yet. Reported as UNKNOWN (the same "eventual
consistency" steady state used by checker-tls when it has no
endpoints yet).
caa_not_authorized: CCADB mapped an observed issuer to a domain
the CAA policy does not list. Reported CRIT.
caa_issuance_disallowed: the policy contains CAA 0 issue ";"
(explicitly disallowing issuance) but a TLS cert was still observed.
Reported CRIT.
caa_issuer_unknown: CCADB has no mapping for the observed issuer
(AKI + DN). Reported INFO; action is to file a CCADB update.
Issuer -> CAA domain mapping (CCADB)
The file checker/AllCAAIdentifiersReport.csv is an unmodified
snapshot of the "CAA Identifiers (V2)" report from the Common CA
Database (https://www.ccadb.org/resources). It is embedded into the
binary via //go:embed but is not committed to the repository.
To fetch or refresh it, run:
go generate ./checker/
This downloads the current CSV from CCADB. No code changes are needed
to pick up a new snapshot: only a re-embed (recompile) is required
after the file is refreshed. Note that the download depends on CCADB
being reachable; go build itself has no network dependency.
The lookup key is:
IssuerAKI (uppercase hex of leaf.AuthorityKeyId), matched
against CCADB's "Subject Key Identifier (Hex)" column.
IssuerDN (Go's leaf.Issuer.String()), matched against CCADB's
"Subject" column after normalization (RDNs sorted by type,
whitespace trimmed, comma/semicolon separators collapsed).
Options
| Id |
Type |
Default |
Description |
domain |
string |
(auto) |
Domain being checked (AutoFill). |
service |
(n/a) |
(auto) |
svcs.CAAPolicy service body. |
Running
# Plugin (loaded by happyDomain at startup)
make plugin
# Standalone HTTP server
make && ./checker-caa -listen :8080