ADR 0029 — Sealed audit hash-chain (WORM) + admission cross-correlation¶
- Status: Accepted (formalized 2026-05-12 with v3.7.0 — Wave 10 + 10-B shipping)
- Date: 2026-05-11 (locked), 2026-05-12 (formalized)
- Deciders: TLSStress.Art project
- Targets: v3.7.0 (sealed chain + cross-correlation); v6.0+ (PCR-hash inclusion via TPM)
- Patent claim family: claim #20 — sealed audit hash-chain with cross-correlation bridge to admission decisions
- Umbrella ADR: 0026
Context¶
Audit logs are the substrate every customer compliance audit relies on. Every prior insider-operator attack pattern includes "and then I edited the audit log": NTP-rewind + replay, delete + gap-conceal, write-then-overwrite via the same root shell that ran the rogue workload. A flat append-only file is a fig leaf — a root shell beats it.
What we need:
- Tamper-evident — any post-hoc edit detectable at the next verification pass, ideally without re-reading the entire log
- Append-only by construction — not by policy, but by the storage layout: appending costs O(1) and overwriting requires re-deriving every subsequent hash
- Cross-correlated with Pod admission decisions so a "rogue pod admitted at 02:14 UTC" lights up the same timestamp in the audit history (forces an attacker who tampers with one to tamper with both)
- Survives WORM storage — works on append-only S3, object-lock buckets, immudb, anything that refuses overwrites at the storage layer
Decision¶
Implement a hash-chain audit log with cross-correlation:
- Each audit entry contains:
- Monotonic sequence number
- UTC timestamp (from a trusted clock proxy, see Wave 10-B)
- Event payload (admission decision, licence check, DLP event, …)
prev_hash= SHA-256 of the previous entry-
entry_hash= SHA-256 of this entry's serialised contents (canonical encoding from ADR 0027) -
Verification is O(n) on log length but incremental: a verifier that already trusts entry N only needs entries N+1..M to extend trust to M. Any in-place edit at entry K breaks the chain at K+1.
-
Cross-correlation bridge (Wave 10-B): the K8s admission webhook (
pkg/ztp-prem-admission/) writes its decision to its own ring buffer and emits an event into the sealed audit log with the same sequence anchor. The dashboard reader (dashboard/src/lib/ztp-prem/admission-correlate.ts) walks both and surfaces correlation gaps as alerts — not silent reconciliations. -
WORM-friendly: the on-disk format is a JSONL stream appended one entry at a time. A delete + re-create pattern fails because (a) S3 object lock refuses overwrite, (b) the chain breaks at the seam.
Consequences¶
Pros - Tampering one log requires tampering the other in a way that re-canonicalises consistently → cost goes from "minutes of root" to "rewriting both stores with valid chains" - Customer SOC 2 audit gets a verifiable artifact instead of a trust-us README - Forensic post-mortem on a real incident becomes possible (you can prove what did happen and what did not) - Foundation for v6.0+ PCR-hash inclusion (the TPM probe will write a measured-boot anchor into the chain at boot, so rebooting into a doctored kernel detectably breaks the chain)
Cons - Verification cost grows linearly with log length — at ~1M entries/day this matters for retention >90d; we plan periodic signed checkpoints in v6.0+ - Cross-correlation gap alerts are noisy if NTP is unreliable — Wave 10-B mitigates with a 30s tolerance window - Append-only means accidental sensitive data can't be redacted — the DLP pre-filter (ADR 0032) has to catch it before the write, not after
Reversibility: medium. The on-disk format can be migrated by shipping a converter + a chain-rebase migration. Cross-correlation semantics could in theory be loosened, but doing so reduces the patent claim and the customer-visible promise.
Related¶
dashboard/src/lib/ztp-prem/sealed-audit/— sealed chain implementationdashboard/src/lib/ztp-prem/admission-correlate.ts— cross-correlation readerpkg/ztp-prem-admission/— admission webhook- ADR 0026 — ZTP-prem umbrella
- ADR 0030 — K8s admission webhook (event source)
- ADR 0031 — TPM 2.0 (future PCR anchor)
Last verified against shipping code: v3.7.0 (2026-05-12).