Audit Logging
An immutable record of who did what, when, and from where — for compliance, security investigation, and customer-facing transparency.
Options
What to Log*
Storage Backend*
User-facing Surface
Decision Points
Are you pursuing SOC 2, ISO 27001, or a similar audit?
If yes
Plan for append-only storage with >= 1 year retention, authentication + admin + mutation scopes, and an auditor-facing export.
If no
Start with auth events in an append-only table; expand scope when a customer or incident forces it.
Do customers need to answer "who did X?" inside your product?
If yes
Build an admin audit log UI — you will be asked for one on every enterprise deal.
If no
Internal-only access is fine until you hear the first request.
Must logs be tamper-evident (hash chain / signing)?
If yes
Chain each log entry by hashing (prev_hash + payload) or sign with an HSM-backed key — required for SOX/HIPAA trail integrity.
If no
Insert-only DB permissions on an append-only table are sufficient for most internal use.
Retention: 30d, 1y, or 7y+?
If yes
Long retention (1y+): tier cold logs to S3/Glacier with lifecycle rules. 7y+ is a SOX/healthcare signal — plan storage costs.
If no
30–90 days in a hot store (primary DB or ClickHouse) covers security review timelines for non-regulated apps.
Should logs include before/after diffs on updates?
If yes
Capture a JSON diff (jsondiffpatch or a custom field-level diff) — essential for customer-facing "who changed this?" questions.
If no
Log action + resource ID only; cheaper but limits forensic value.
Log reads (access logs) or only writes?
If yes
Sample or scope to sensitive resources only — full read logging often produces 100x the write volume. Required for HIPAA.
If no
Write-only logging is the default — covers the overwhelming majority of compliance and forensics needs.
Store audit logs separately from operational DB?
If yes
Stream to a dedicated store (ClickHouse, S3, or SIEM) — isolates audit traffic from app queries and allows differing retention/permissions.
If no
An append-only table in the primary DB is simpler and sufficient at early scale.
Cryptographic signing of entries required?
If yes
Sign each entry with an HSM-backed key (AWS KMS) — provides non-repudiation beyond hash chaining.
If no
Hash-chain or insert-only permissions are enough until an auditor asks.
Exportable as SIEM-compatible (CEF, JSON)?
If yes
Offer structured JSON export and optionally CEF/LEEF for enterprise SIEMs (Splunk, QRadar) — usually gated behind a plan.
If no
A simple CSV export covers most self-serve customers.
Real-time alerts on specific events?
If yes
Route high-signal events (privilege escalation, mass delete) through a streaming pipeline (Kinesis/Kafka) into alerting — PagerDuty or customer Slack.
If no
Batch nightly review is enough for low-stakes environments.
Distinguish system actions from user actions?
If yes
Model actor as a typed union (user | system | api_key | admin) — required for any meaningful forensic query.
If no
A single actor_id field works short-term but becomes ambiguous fast — avoid.
Log IP and user-agent on every action?
If yes
Capture IP + user-agent + geo on every event — standard for security review and fraud investigations.
If no
Auth events only is the bare minimum; expect to backfill later.
Retain deleted resource IDs in logs indefinitely?
If yes
Keep resource IDs forever — critical for "what happened to record X?" questions after deletion.
If no
Honor GDPR right-to-erasure by tombstoning PII but preserving action records with hashed IDs.
Redact/tokenize PII in log bodies?
If yes
Run an allowlist + regex redaction pass at the producer before write — tokens, emails, card numbers never land in the log store.
If no
Acceptable only if logs never leave your trust boundary — avoid.
Log admin impersonation with both identities?
If yes
Record both real_actor and impersonated_user on every event during an impersonation session — required for SOC 2 and customer trust.
If no
Single-actor logs make it impossible to tell who really acted — always log both.
Is write-once storage (S3 Object Lock) a compliance need?
If yes
Stream logs to S3 with Object Lock compliance mode — cheapest credible WORM store. Neither you nor an attacker can rewrite.
If no
Insert-only DB table is enough until an auditor requires immutable storage.
Tradeoffs
Read amplification — every authenticated read produces a log write
Two storage systems to operate and keep in sync; queries may need to federate
Tamper-evidence relies on DB role permissions — insufficient for some compliance regimes
Go Deeper
Designing the audit event schema
The schema you pick now constrains every future query and integration.