compliance.tf

The Audit Trail

  • Twelve acts produce a record: creating and archiving a project, binding, promoting, rolling back, the three waiver decisions, publishing, approving, replacing module aliases, and changing the organization's coverage-blocking setting.
  • A record carries five things — who, what act, what was acted on, a small detail payload, and when. Nothing else. There is no request id, no source address, no client identifier.
  • Each record is written in the same atomic operation as the change it describes, so the trail cannot disagree with what actually happened.
  • The trail records successful changes only. A refused promotion, a denied permission, and a read of any kind leave no trace.
  • Records are retained for a bounded window, not forever. If your framework needs longer, export on a schedule and treat your own export as the system of record.

Why there is a trail

A posture that can change has to be able to answer for its changes. "Production enforces this control set" is a statement about now; an auditor's question is almost always about then — what was live on the date of the incident, who put it there, and what exceptions were open at the time.

compliance.tf answers the what with immutable snapshots, described on configs and snapshots. The audit trail answers the who, the when, and the which. Between them, a past state is reconstructible: the trail tells you which snapshot an environment was pointed at on a given date, and the snapshot itself — being immutable — still holds exactly what that meant.

That division matters for reading the trail correctly. The trail records decisions and pointers, not content. A publish record names the snapshot that was created, not the control set inside it. A promotion record names the snapshot that was promoted, not what changed as a result. The content is not duplicated into the trail because it does not need to be: the object it points at cannot change.

What produces a record

Every act that changes what an environment serves, or changes the governance around it, writes a record:

  • Structural changes to a project — creating one, archiving one, replacing its module aliases.
  • Changes to what an environment serves — binding a snapshot, promoting one, rolling back to the previous one.
  • Waiver decisions — proposing an exception, approving it, revoking it.
  • Authoring milestones — publishing a draft into a snapshot, approving a snapshot.
  • One organization-level setting — the switch that decides whether uncovered framework coverage blocks a promotion or merely warns.

The complete catalogue, with the exact action name each writes and what its detail payload carries, is in the operator section below.

Two things are worth stating in the same breath, because readers reliably assume otherwise. Editing a draft writes no record, and neither does creating a config. Drafts are working material; the publish is the moment that gets recorded, and the snapshot it produces is the durable artifact. And membership changes, role changes, and registry token operations are not in this trail at all — see what the trail does not record.

What a record contains

FieldWhat it holds
ActorThe stable subject identifier of the authenticated caller. Never a token, a service, or an inferred identity — every recorded act is carried out by a signed-in person.
ActionThe name of the act. One of a fixed set; see the catalogue below.
TargetThe thing acted on. The project and environment for a bind, promote, rollback, or waiver decision; the project alone for project-structural changes; the snapshot for a publish or approval; the organization for the coverage setting.
DetailA small payload specific to the action — identifiers and flags, not content. Sometimes empty.
TimeWhen the act happened, to microsecond precision, in UTC.

When the trail is read back, the actor's email address is joined in where it can be resolved from current organization membership. That join is a display convenience, not part of the record — the identifier is what is stored.

Records are written with the change, not after it

The record and the change it describes are written as one operation that either fully succeeds or fully fails. This holds for all twelve actions.

The consequence is the property that makes the trail worth having: there is no window in which an environment is repointed without a corresponding record, and no record describing a change that did not land. If a promotion is refused because the binding moved underneath it, the promotion and its record are both discarded together. If a project archive is refused because the project does not exist, no record is written for the attempt.

No product action edits or deletes a record. There is no amend, no correction, no redaction, and no delete — not for an owner, not for anyone.

Reading it

Reading the trail requires the audit:read permission, which owner and admin hold and member does not. It is not granted by the approver capability. See access control for the full model.

That is a deliberate asymmetry: a member can carry out acts that write records without being able to read the record of them. If your control narrative depends on the acting engineer being able to review their own history, plan for someone with the permission to pull it for them.

A second, narrower view of the same data appears in the governance summary, where the most recent records are shown alongside pending approvals and expiring waivers. That slice is gated on the same permission, so a member reading the summary sees it with the recent-activity section empty rather than being refused the whole page.

Retention

Records are kept for a bounded window and then removed. The window is a deployment setting rather than a published figure — ask us for the current value if you need it for a control narrative.

Removal is not a product action; it is the datastore expiring rows that have reached their retention age. Nothing in the product can accelerate it, and nothing can extend it for an individual record.

The practical consequence: if a framework requires retention longer than that window, the platform is not your system of record. Export the trail on a schedule into whatever you already use for long-lived evidence, and treat the export as authoritative. This is the one place where relying on the platform alone will let you down at exactly the wrong moment, because the gap only becomes visible when an auditor asks for a period that has already aged out.

What the trail does not record

Stated plainly, because each of these is something a reader may reasonably assume is captured:

  • Failed and refused acts. A promotion the gate blocked, a request rejected for lack of permission, a bind that lost a concurrency race — none of these write anything. The trail is a record of what happened, not of what was attempted.
  • Reads. Nobody's viewing of a snapshot, an environment, or the trail itself is recorded. A terraform init resolving against a binding is not recorded either — see module request resolution for what that path does.
  • Draft edits and config creation. Neither writes a record. What was in a draft before a publish is not recoverable from the trail.
  • Membership, roles, and invitations. Adding a member, changing a role, granting or removing the approver capability, and removing someone are not in this trail.
  • Registry tokens. Minting, using, and revoking a token write nothing here. Tokens carry their own creator attribution — see registry tokens.
  • Request context. No source address, user agent, request id, or session identifier is stored. You cannot tell from a record where an act came from.
  • Most organization settings. Exactly one setting change is recorded. Others are not.

What this is, and is not, as evidence

Be precise about the claim here, because overstating it is worse than understating it.

What the records demonstrate. For any act in the catalogue, the trail shows that a specific identified person carried out a specific act against a specific object at a specific time, and that the record was created inseparably from the change itself. Combined with the immutability of snapshots, that supports a reconstruction of what a given environment enforced on a given date and who put it there.

What they do not do. These records do not, on their own, satisfy any named control or clause in any framework. compliance.tf does not claim they do, and you should not either. Whether a given control's requirements are met by this trail — with your retention arrangements, your access model, and your process around it — is your auditor's determination, not a property of the product. Claims made ahead of that determination are the ones that come apart under examination.

Where the boundary sits. This trail covers changes to compliance posture inside compliance.tf. It is not a change-management system for your infrastructure, not an access log, and not a security monitoring feed. It is also distinct from what the modules themselves produce for an auditor — prevention, pre-apply, and post-apply evidence about your actual AWS resources — which is covered in audit evidence. The two are complementary: the modules evidence what your infrastructure enforced, this trail evidences who decided it should.

Operating the trail

The rest of this page is the operator's half: the complete action catalogue with the target and detail each record carries, how to query a window, the precise limits on what the records can tell you, and a recipe for reconstructing a past state from them.

On this page

Ask AI about this

Help improve this page