- Unexpected statefile changes — someone runs
terraform applyoutside your pipeline. A laptop apply updates the statefile and the world together, so they still agree and a scheduledterraform plancomes back empty. This page covers detecting this type. - Non-Terraform changes — someone edits the world directly via the cloud console, API, or CLI, so reality no longer matches the statefile. See Detecting non-Terraform changes.
Why a plan can never catch this
terraform plan compares the statefile to the world. An out-of-CI apply changes both in lockstep, so the comparison stays clean — the plan is structurally blind to it. What has changed is the statefile itself: it is now a file your pipeline never produced. Detecting that requires a record of where every statefile came from — a provenance system.
How Kosli detects it
The mechanism is attestation plus continuous reporting against a Kosli Environment:- At apply time, the pipeline attests the Terraform statefile as an artifact into the Kosli Environment. Attestation fingerprints the file and records that your pipeline produced it, linked to the git SHA — establishing its provenance.
- Continuously, a scheduled Kosli reporter Lambda snapshots the live statefile from S3 into the same Environment. The Environment’s policy requires every artifact to have known provenance.
Prerequisites
- Terraform is applied through CI/CD, not from laptops, as the normal path — with remote, locked state (for example, an S3 backend with the native S3 lockfile or DynamoDB).
- Keyless CI authentication to your cloud (for example, GitHub OIDC).
- A Kosli account and API token.
- A Kosli Environment for each Terraform environment you want to protect.
- The Kosli reporter Lambda deployed to snapshot the statefile into that Environment on a schedule.
Setting it up with kosli-dev/tf
Everything above is implemented at github.com/kosli-dev/tf: a thin Terraform wrapper (tf) and a set of reusable GitHub Actions workflows, both open source under the MIT license. You can call the workflows directly, or borrow their shape for your own CI.
The wrapper
tf is a drop-in replacement for terraform that removes the manual bookkeeping. It selects the correct -var-file for your active AWS profile and region, and injects the S3 backend config so you never hand-manage it. The backend is derived deterministically:
tf plan saves a binary plan for later inspection; tf apply appends -auto-approve (the plan has already been reviewed, and CI has no interactive prompt). Locally you wrap it in your credential helper, for example aws-vault exec staging -- tf plan.
The apply workflow
The reusableapply.yml workflow runs the plan steps plus tf apply, then attests the plan, the apply log, and the statefile into your Kosli Environment. A caller workflow that applies on merge:
The
drift-plan artifact belongs to the second drift type — the marker file used by the scheduled plan loop in Detecting non-Terraform changes. The same apply workflow attests both, so one setup covers both types.What a detection looks like
Someone runsterraform apply from a laptop. The statefile in S3 is rewritten with content your pipeline never attested. On its next snapshot the Kosli reporter Lambda finds an artifact with no known provenance, and the Environment turns non-compliant. The Environment’s snapshot history shows exactly when the unrecognized statefile appeared and what its fingerprint is — a concrete starting point for the investigation, and a durable record for the audit trail.
Hardening
Monitor the monitor
Monitor the monitor
This is the most dangerous failure mode. If the reporter Lambda silently stops running, no new evidence arrives to contradict the last snapshot — so the Environment looks green forever, even as unattested statefiles accumulate. Treating “the dashboard is green” as proof of cleanliness, without also verifying the Lambda is running on schedule, is a misuse of the control. Add a heartbeat or alert on “no snapshot in N intervals”.
Least privilege
Least privilege
The reporter Lambda needs read access to the state bucket and the ability to report snapshots to Kosli — nothing more. It must never hold apply permissions.
Implementation checklist
- Terraform is applied through CI/CD, with remote, locked state.
- Each apply attests the statefile (plus plan and apply log) into a Kosli Environment.
- The Kosli reporter Lambda snapshots the live statefile from S3 into the Environment on a schedule.
- The Environment’s policy requires known provenance for every artifact.
- The reporter Lambda is monitored for silent failure (heartbeat / not-run alert).
- Snapshot cadence is tuned per environment.
Related
- Drift Detection (SDLC-CTRL-0018) — the control both drift-detection tutorials implement.
- Detecting non-Terraform changes — the other drift type: console and API edits a plan can catch.
kosli-dev/tf— the reference wrapper and reusable workflows.- Environments — the Kosli primitive that carries the compliance signal.
- Flow template reference — declaring attestations and artifacts.