Safeguard
Best Practices

An Audit Log You Can Actually Answer Questions With

During an incident you get asked three questions. If answering takes a week of grepping application logs, you do not have an audit log, you have debugging output that happens to contain some of the answer.

Daniel Osei
Security Analyst
6 min read

During an incident you will be asked three questions: who accessed this record, what did this account do between these dates, and when did this permission change. If answering takes a week of grepping application logs, you do not have an audit log. You have debugging output that happens to contain some of the answer.

An audit log is a different artifact with a different purpose. This post is what it needs to contain and who should be able to touch it. For whoever will be asked those questions.

Application logs are not audit logs

They overlap and they are built for opposite goals.

Application logs are for diagnosing behaviour. They are verbose, unstructured in places, retained briefly, written by every part of the codebase, and nobody minds if a noisy line is removed to reduce cost.

An audit log is evidence. It records a defined set of events in a stable format, it is complete for those events, it is retained for as long as an obligation requires, and its integrity matters because it may be used to establish what happened in a dispute.

Trying to satisfy the second with the first is the common failure, and it shows up when someone asks a question that requires completeness. You cannot establish that something did not happen from a log that drops lines under load.

The events worth recording

Not everything. A defined list, agreed once:

  • Authentication: success, failure, method, and multi-factor challenges.
  • Authorisation denials. Successes are usually too voluminous; denials are cheap and are what an investigation looks for.
  • Privilege and role changes, including group membership.
  • Access to sensitive records, at whatever granularity is meaningful for your data.
  • Bulk operations: exports, mass updates, deletions.
  • Configuration changes that affect security behaviour, including feature flags.
  • Impersonation or support access, start and end.
  • Credential lifecycle: tokens issued, rotated, revoked.
  • Administrative actions in your own back office.

If a question during an incident would be answered by one of these and it is not recorded, that is the gap to close first.

The fields

Sparse records force reconstruction later. Each entry needs:

Actor, as a stable identifier rather than a display name, plus the real actor separately when the action was performed through impersonation. An audit log that shows only the impersonated user is actively misleading, and it is the field most often missing.

Action, from a controlled vocabulary. Free text here means you cannot query by action type in two years.

Object: what was acted on, with a stable identifier, and its tenant.

Timestamp, with a timezone or in UTC unambiguously. A zone-less local time is worth much less in a cross-region investigation.

Source: IP address taken from a header you can actually trust, and user agent. If you take the leftmost value of a forwarded header, the address is attacker-controlled and your audit record is fiction.

Result: succeeded, denied, failed.

Correlation id, linking the audit entry to the request and to your application logs, so you can pivot between them.

Integrity

The property that separates an audit log from a table.

Write to a separate store with different credentials. If your application's database user can delete audit rows, an attacker with application-level access can erase their own trail.

Append-only. No update path, no delete path in the application at all. Retention is enforced by the store's lifecycle policy rather than by code that could be called.

Ideally outside the same blast radius: a different account or project, where the production role has write access and no delete access. Several cloud log services offer exactly this.

Consider tamper evidence if you are likely to face a dispute: hash chaining, or writing to an append-only service with an integrity guarantee. This is more than most organisations need, and it is worth knowing it exists before the situation where you need it.

Make it answerable

The test is not whether the events are recorded, it is whether you can answer a question under pressure. Try these, timed:

  • Every action by account X between two dates.
  • Everyone who accessed record Y, ever.
  • Every permission change in the last ninety days, and who made each.

If any takes more than a few minutes, fix the queryability rather than adding more events. That usually means structured fields and an index on actor, object and time, and it means storing the audit log somewhere designed for querying rather than in flat files you grep.

Retention needs a decision

Audit logs are the one category where retaining longer is often required rather than risky, because obligations and investigation windows can run to years. Intrusions are frequently discovered months after they began, and logs that rolled off at ninety days cannot tell you when it started.

Pick the number deliberately, from your regulatory obligations and your realistic detection lag, and write down which one drove it. Then check what your platform actually does, because the default retention on several services is much shorter than people assume.

The concession

Comprehensive audit logging is expensive: in storage, in the engineering effort to instrument every path consistently, and in the discipline to keep it consistent as the product changes. A small team instrumenting everything will produce a large volume nobody has time to query, which is a cost with no benefit.

The proportionate version is to be complete about a short list rather than partial about a long one. Ten event types recorded consistently, with the fields above, beat fifty recorded sometimes. And the events that matter most are the boring ones: who logged in, who was denied, who changed a permission, who exported data.

The implication

The value of an audit log is realised entirely in the future, under pressure, by someone who did not design it, answering a question they did not anticipate.

So the design test is not completeness in the abstract. It is whether your successor can answer "what did this account do" in five minutes, and whether they can trust the answer.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.