A deployment attestation primitive for Terraform apply. Cryptographic integrity, WORM storage, and offline verification.
This is a focused primitive: tamper-evident deployment history with offline verification. Use cases like compliance audits, incident forensics, and vendor accountability are downstream applications - not guaranteed outcomes.
The primitive composes existing, well-defined building blocks: KMS asymmetric signing, SHA-256 chaining, S3 Object Lock in COMPLIANCE mode, and Lambda orchestration. Nothing novel. The value is the composition and the offline verification story.
Verify in 60 Seconds
Before reading further, prove it works:
git clone https://github.com/StudioAsCode/terraform-aws-compliance-evidence
cd terraform-aws-compliance-evidence
pip install -r requirements.txt
python3 examples/demo/verify_offline.py
You should see:
[INFO] Verifying evidence bundle: examples/demo
[INFO] Verifying manifest signature...
[SUCCESS] Manifest signature valid
[INFO] Verifying file hashes...
[SUCCESS] All 5 file hashes valid
[INFO] Verifying hash chain...
[SUCCESS] Hash chain valid (4 artifacts)
[INFO] Verifying artifact signatures...
[SUCCESS] All 4 artifact signatures valid
[SUCCESS] All verification checks passed
Note: The demo uses a locally-generated RSA keypair. Production deployments use AWS KMS for key custody.
Now edit any artifact in examples/demo/artifacts/ and run again. Verification fails immediately - the verifier is fail-fast. That is the primitive.
Tamper Demo
python3 - <<'PY'
import json
p="examples/demo/artifacts/0001.json"
d=json.load(open(p))
d["tampered"]=True
open(p,"w").write(json.dumps(d, indent=2, sort_keys=True) + "\n")
PY
python3 examples/demo/verify_offline.py || true
git checkout -- examples/demo/artifacts/0001.json
Expected output contains: [ERROR] Hash mismatch for artifacts/0001.json
What Offline Verification Proves
Offline verification is fail-fast and layered:
- Manifest signature - proves the file index (manifest.json) was signed by the attestation key
- File hashes - proves every referenced file matches its recorded SHA-256 (detects edits and deletions)
- Hash chain - proves the artifacts form an ordered, tamper-evident sequence within the exported set
- Artifact signatures - proves each artifact payload was signed by the same key
Any modification to a manifest-referenced file causes verification to fail immediately with a nonzero exit. Completeness across time requires export from genesis or a trusted checkpoint.
Trust Model
What is proven. What is not.
- Artifact integrity (signature valid)
- Signer key identity (KMS key K signed this)
- Ordering within exported set (hash chain continuous)
- Immutability during retention (Object Lock enforced)
- Completeness across all time (unless chain anchored from genesis)
- Absence of out-of-band changes (only attested events recorded)
- Signer identity not compromised (depends on IAM/CI controls)
- Deployment correctness (records what happened, not if it was right)
If any of these boundaries are unclear, the primitive is not useful to you. Read the assumptions before deploying.
The Primitive
A signed attestation artifact describing a deployment event.
Signature proves the artifact was signed under key K. Attribution to a person or system depends on KMS key policy, CI identity controls, and integrity of captured context.
How It Works
flowchart LR
A[Terraform apply] --> B[Attestation Lambda]
B --> C[Build canonical artifact JSON]
C --> D[KMS Sign - RSA]
C --> E[sha256 - artifact]
E --> F[Link prev_hash to new_hash]
F --> G[DynamoDB chain head]
D --> H[S3 Object Lock - COMPLIANCE]
C --> H
E --> H
H --> I[Offline export bundle]
I --> J[Offline verifier]
J --> K[Verify signature and chain]
Hash Chain
flowchart LR
A1[artifact_001<br/>hash=h1<br/>prev_hash=genesis] --> A2[artifact_002<br/>hash=h2<br/>prev_hash=h1]
A2 --> A3[artifact_003<br/>hash=h3<br/>prev_hash=h2]
A3 --> A4[artifact_004<br/>hash=h4<br/>prev_hash=h3]
Each artifact includes the hash of the previous artifact. If any record is altered, removed, or reordered, the chain breaks. The first mismatched hash identifies where tampering occurred.
Offline Export Bundle
flowchart TD
Z[bundle.zip] --> A[artifacts/]
Z --> B[public_key.pem]
Z --> C[verify_offline.py]
A --> A1[0001.json]
A --> A2[0002.json]
A --> A3[0003.json]
The bundle is self-contained. Auditors can verify bundle integrity without AWS API access. They need the bundle and the included public key.
What Is Implemented in v1
Supported by the Primitive (Use Cases)
These are downstream applications. The primitive enables them; it does not guarantee outcomes.
| Use Case | What Attestation Provides |
|---|---|
| Change management | Signed artifact with deployment details and caller identity |
| Incident forensics | Exportable chain for time window, verifiable sequence |
| Rollback validation | Signed artifact for rollback action, comparable to target state |
| Multi-team handoffs | Each team’s changes signed separately, boundary verifiable |
| Vendor accountability | Vendor deploys signed with their CI identity, timestamped |
| Compliance audits | Exportable evidence bundle, offline verifiable |
If you have heard "that is not what we deployed" or "we rolled it back" or "the vendor broke prod," the primitive applies. Whether it solves your problem depends on your deployment and verification discipline.
Roadmap / Planned Integrations
Not implemented. Future work.
Assumptions for Correct Operation
The primitive works correctly if:
- KMS key policy restricts signing to expected roles and pipelines
- CI identity cannot be forged (OIDC audience/subject constraints enforced)
- Artifact canonicalization is deterministic and matches the signing spec
- S3 Object Lock is configured correctly (COMPLIANCE mode, retention period set)
- Export bundle is contiguous from a known checkpoint or includes checkpoint hash
If any assumption is violated, the guarantees do not hold.
Known Limitations
Areas for future improvement:
- Key rotation story - how to bind a historical chain to a stable public key identity over time
- Public key provenance - verifiers must trust the included public key is authentic; out-of-band verification against KMS key ARN is recommended
- Clock trust - timestamps depend on CI/Lambda time sources; no external timestamping anchor yet
- Chain completeness - proving no artifacts were omitted requires anchoring from genesis or a trusted checkpoint
To dispute the evidence, reviewers must find an implementation bug or challenge the trust model assumptions (which are stated above).
Common Questions
These questions come up repeatedly. The answers define the boundaries of what this primitive does and does not provide.
Does offline verification prove “this is everything”?
No. Offline verification proves integrity and ordering of the exported set. Completeness across all time requires either export from genesis or a trusted checkpoint hash published out-of-band.
How do I trust the public key in the bundle?
You must validate the included public_key.pem fingerprint against an expected value obtained out-of-band. Concrete mechanism: publish the fingerprint in a signed Git tag or signed GitHub release asset. Auditors compare the bundle fingerprint against the published value before accepting the evidence.
What happens if someone omits artifacts from the export?
The export may still verify if internally consistent. To make omission detectable, use checkpoints: periodically sign and publish the chain head hash, then compare against the exported chain head.
Does this detect out-of-band changes to infrastructure?
No. Attestation only records events you choose to attest. Out-of-band changes (manual console edits, other tools) are not captured. This is an evidence layer, not a drift detection system.
Full FAQ: FAQ.md in the repository covers key rotation, algorithm details, audit requirements, and more.
The AWS Stack
This composes AWS’s proven building blocks. No custom cryptography.
Try It
GitHub repo: StudioAsCode/terraform-aws-compliance-evidence
Start here: README.md
Offline verification demo: examples/demo
Issues/Discussions: GitHub Issues
The Difference
Logging tells a story. Attestation provides proof.
If you can export a bundle, hand it to a third party, and they can verify integrity and sequence without cloud access, you have crossed the line from “trust me” to “verify me.”
That is the primitive. Use cases are yours to build.