No description
  • Go 97.5%
  • Makefile 1.5%
  • Dockerfile 1%
Find a file
2026-04-29 12:42:43 +07:00
checker Include AllCAAIdentifiersReport.csv to simplify the build 2026-04-29 12:42:43 +07:00
plugin Initial commit 2026-04-26 19:44:52 +07:00
.gitignore Include AllCAAIdentifiersReport.csv to simplify the build 2026-04-29 12:42:43 +07:00
Dockerfile docker: add HEALTHCHECK probing /health 2026-04-26 19:44:52 +07:00
go.mod docker: add HEALTHCHECK probing /health 2026-04-26 19:44:52 +07:00
go.sum docker: add HEALTHCHECK probing /health 2026-04-26 19:44:52 +07:00
LICENSE Initial commit 2026-04-26 19:44:52 +07:00
main.go Initial commit 2026-04-26 19:44:52 +07:00
Makefile Initial commit 2026-04-26 19:44:52 +07:00
NOTICE Initial commit 2026-04-26 19:44:52 +07:00
README.md Initial commit 2026-04-26 19:44:52 +07:00

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

  1. The host runs this checker on a svcs.CAAPolicy service.
  2. Collect unmarshals the service body into a list of (flag, tag, value) entries. No network.
  3. 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).

Observation payload

This checker does not publish endpoints or add a new observation schema. Under its own observation key caa_policy it returns a pass-through view of the zone-side CAA records:

{
  "domain": "example.net",
  "records": [
    { "flag": 0, "tag": "issue",     "value": "letsencrypt.org" },
    { "flag": 0, "tag": "issuewild", "value": ";" }
  ],
  "run_at": "2026-04-22T12:34:56Z"
}

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:

  1. IssuerAKI (uppercase hex of leaf.AuthorityKeyId), matched against CCADB's "Subject Key Identifier (Hex)" column.
  2. 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