Audit Attestation
The audit log is hash-chained per Org, but a chain is only useful if you can prove a specific entry is in it without trusting our infrastructure. The attestation subsystem publishes RFC 6962-shaped Merkle roots over windows of audit_log.this_hash entries, signs them with a KMS-managed key, and serves inclusion proofs that an offline verifier can check against the published root.
Why RFC 6962
RFC 6962 is the Certificate Transparency Merkle construction. We adopt the same domain-separation rules so anyone can plug Tetrapus roots into existing CT-compatible verification tooling.
- Leaf hash:
H(0x00 || leaf_bytes) - Inner node:
H(0x01 || left || right) - Odd nodes are promoted up the tree, never duplicated (matches RFC 6962 §2.1)
MerkleProof::verifyrequiresleaf_countto reconstruct the same promotion pattern
Root construction
A scheduled job inside tetrapus-server reads the next window of audit_log rows for an Org, hashes each this_hash as a leaf, builds the tree, signs the root with the Org's audit-scope KMS binding, and persists the result.
attestation_roots table
| Column | Type | Notes |
|---|---|---|
| id | UUID | PK |
| org_id | UUID | FK orgs(id), cascade |
| period_start / period_end | TIMESTAMPTZ | Window covered |
| audit_seq_start / audit_seq_end | BIGINT | Sequence range |
| merkle_root | BYTEA | 32 bytes (SHA-256) |
| signature | BYTEA | ES256 r||s, 64 bytes |
| signing_key_kid | TEXT | JWKS kid for verification |
| published_at | TIMESTAMPTZ | DEFAULT now() |
REST routes
All three endpoints are mounted under /api/v1/admin/attestation. Reading roots requires the standard admin role; /verify is unauthenticated by design — it is intended to be called from an offline auditor laptop.
| Method + path | Purpose |
|---|---|
| GET /admin/attestation/roots | Paged list of published roots for the caller's Org |
| GET /admin/attestation/roots/{id}/proof?seq=N | Merkle inclusion proof for audit row at seq N |
| POST /admin/attestation/verify | Offline verifier endpoint — returns OK iff proof reconstructs root |
Inclusion proof shape
A proof is the ordered list of sibling hashes a verifier needs to walk from the leaf back to the root, plus the leaf index and total leaf count.
Offline CLI
tetrapus-admin attestation verify wraps the same logic that /admin/attestation/verify implements. Auditors can pull a root + proof + leaf hash from the API and verify offline against the published JWKS.
tetrapus-admin attestation verify \
--root ./roots/2026-04-01.json \
--proof ./proofs/seq-12345.json \
--leaf $(tetrapus-admin audit hash --seq 12345)
# OK: leaf 12345 is included under root id=ae2d… signed by kid=jwk_audit_2026q2 Related
- – Audit Trail — the underlying hash chain
- – KMS Backends — how roots are signed
- – CMEK / BYOK — the audit scope binding
- – Back to Enterprise
Questions?
Reach out for help with integration, deployment, or custom domain codecs.