The Audit Vault
A record of who did what that survives the person who wants it gone.
The incident
The database was dropped at 2 a.m. The application logs that would have said by whom rotated out — and the attacker's first move, hours earlier, had been to clean the rest. Forensics had a disaster and no narrative.
Why the obvious approach fails
Application logs are built for debugging, not evidence: they rotate, they're mutable, they live on infrastructure the attacker may control, and they log what developers found interesting rather than what investigators need. An audit trail is a different artifact with a different threat model — it must assume the adversary has admin credentials, because in the incidents that matter, they do. That means immutability enforced below the application: storage where delete doesn't exist as a permission.
The standard
- Security-relevant actions (auth events, permission changes, data exports, admin operations, financial mutations) write to a dedicated audit stream — separate from application logs.
- Audit storage is WORM: append-only object storage or equivalent, with UPDATE/DELETE disabled at the infrastructure/IAM level, plus retention locks.
- Every entry carries the five Ws: who (resolved identity), what, where (IP/endpoint), when (trusted timestamp), and why (correlation ID to the triggering request).
- Volume anomalies on sensitive reads (one user, 500 records, one minute) raise alerts in near-real-time.
- Audit write failures are loud — a system that can't record must degrade visibly, not silently.
How Cortex validates it
At plan time
The blueprint enumerates auditable actions; any sensitive operation without an audit hook fails plan review.
At validation
assert: audit_bucket.iam excludes delete, put_overwriteassert: sensitive_actions ⊆ audited_actionsassert: entries.fields ⊇ [who, what, where, when, correlation_id]Assertion syntax is illustrative.
At review
The approver sees a tamper attempt against the vault fail, and a sample trail reconstructing one request end-to-end.