Audit retention¶
Every state-changing action in Ampora produces an audit event. Audit events live in three tiers:
- Hot table (
audit_events) — fast queries, full structuredbefore/afterJSON, indexed by tenant + entity. - Archive table (
audit_event_archive) — same shape, no non-essential indexes, optimised for storage. - Purged — the row is gone for good.
The audit retention service runs on the leader instance, sweeps both tables, and moves rows between tiers based on configured windows.
Settings¶
AuditRetention:
HotDays: 90 # default: 90
ArchiveDays: 2555 # default: 7 years
SweepIntervalMinutes: 60
| Key | Effect |
|---|---|
HotDays | Rows older than this in the hot table are moved to the archive |
ArchiveDays | Rows older than this in the archive table are deleted |
SweepIntervalMinutes | How often the leader runs a sweep |
Both windows are inclusive — a row aged exactly HotDays is kept hot for one more sweep, then moved.
Reading archived events¶
The audit log UI only queries the hot table by default. To search archived events, the page has an "Include archive" toggle:
- The toggle is gated by
Adminrole. - Searches with the toggle on are slower (no per-actor index on the archive table) — they typically take a second or two for a year-wide query.
- The audit log of the audit log: opening the archive emits its own audit event, with the query parameters.
API users can query the archive directly via the ?includeArchive=true query parameter on /api/audit/events.
Compliance presets¶
| Compliance regime | Recommended HotDays | Recommended ArchiveDays |
|---|---|---|
| SOC 2 (typical) | 90 | 365 |
| HIPAA | 30 | 2190 (6 years) |
| PCI-DSS | 90 | 365 |
| GDPR | 30 | as long as the lawful basis lasts |
| ISO 27001 | 90 | 1095 (3 years) |
These are starting points, not legal advice. Confirm the actual window your auditor expects.
What is logged¶
Every of these events is recorded with actor, timestamp UTC, entity ID, and a before / after JSON snapshot:
- Authentication — login, logout, role assumption.
- Configuration — create, edit, publish, archive.
- Rollout — create, start, pause, resume, abort, rollback.
- Group — create, edit, member add/remove, soft-delete, restore.
- Token — issue, revoke, redeem, pool create, pool admin secret rotate.
- Identity — issue, revoke, hard-delete (only for Unbound).
- Policy — create, edit, publish (with approver), retire.
- PKI — signing-key create, activate, retire; CRL publish; OCSP signer rotate.
- Federation — peer create, edit, delete, ping, every aggregator call (origin and target).
- GitOps — source create, sync run start/end, per-file errors.
- Tenant — create, theme change, identity-mapping change.
What is not logged¶
- Read-only queries to the application itself. The Postgres audit extension can record those if you need it; Ampora does not by default.
- Telemetry payloads flowing through agents — Ampora is not an APM.
- OpAMP heartbeats — too high-volume to be useful in an audit log. They are summarised as "agent connected for X minutes" via the agent status history instead.
Performance¶
The retention sweep is designed to be invisible:
- Each sweep moves rows in batches (default 5 000) with a small commit pause between batches.
- Both tables are partitioned-friendly; if your cluster grows past the comfortable single-table size, the migration to native partitioning is documented in ADR-034.
- Indexes on the archive table are minimised on purpose. Heavy archive searches should be rare; if they are not, add the index on the specific column you query and accept the storage cost.
Tamper-evidence¶
Audit rows are append-only. The application never updates an audit event in place; corrections are new audit events that reference the original. There is no UI or API to mutate audit_events rows.
For deployments that need cryptographic tamper-evidence (each row signing the previous row's hash), ADR-034 documents the integration with RFC-3161 timestamping (ADR-046). It is an opt-in for regulated customers.