Blog

Deployment Attestation - Cryptographic Proof for Infrastructure Changes

cer4sco cer4sco • Founder

A deployment attestation primitive for Terraform apply. Cryptographic integrity, WORM storage, and offline verification. Use cases are downstream applications, not guaranteed outcomes.

LEVEL 300 Advanced • Platform Engineers & Security Architects
Prereqs: aws-kmss3-object-lockterraformhash-chainsdigital-signatures
12 min read
Deployment Attestation - Cryptographic Proof for Infrastructure Changes

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:

  1. Manifest signature - proves the file index (manifest.json) was signed by the attestation key
  2. File hashes - proves every referenced file matches its recorded SHA-256 (detects edits and deletions)
  3. Hash chain - proves the artifacts form an ordered, tamper-evident sequence within the exported set
  4. 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.

Proven by Attestation
  • 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)
Not Proven by Attestation
  • 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.

  • 1 What was deployed - Plan/apply summary, resource counts, metadata
  • 2 When it was attested - Timestamp recorded at creation, preserved immutably
  • 3 Who initiated it - Claimed caller identity and CI context in the signed artifact
  • 4 Integrity proof - KMS signature over the artifact
  • 5 History proof - SHA-256 hash chain linking deployments
  • 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]
  • 1 Input - Terraform apply output, workspace, commit, pipeline run, caller ARN
  • 2 Construct - Canonical JSON artifact with byte-exact representation defined by the signing spec
  • 3 Sign - KMS Sign over artifact digest (RSA, PKCS1 v1.5, SHA-256)
  • 4 Link - Compute sha256(artifact) and store previous_hash reference
  • 5 Store - S3 Object Lock in COMPLIANCE mode with retention
  • 6 Index - DynamoDB stores chain head, sequence pointers
  • 7 Export - Bundle artifacts, public key, and verifier script

  • 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

  • KMS signing - RSA 2048, PKCS1 v1.5, SHA-256 digest mode
  • SHA-256 hash chain - Each artifact links to previous
  • S3 Object Lock - COMPLIANCE mode, configurable retention
  • Offline verification - Standalone Python script, no AWS dependencies
  • CLI tool - Query, verify, export artifacts
  • GitHub Actions workflow - Reusable workflow for CI/CD
  • Demo bundle - Verify without deploying infrastructure

  • Supported by the Primitive (Use Cases)

    These are downstream applications. The primitive enables them; it does not guarantee outcomes.

    Use CaseWhat Attestation Provides
    Change managementSigned artifact with deployment details and caller identity
    Incident forensicsExportable chain for time window, verifiable sequence
    Rollback validationSigned artifact for rollback action, comparable to target state
    Multi-team handoffsEach team’s changes signed separately, boundary verifiable
    Vendor accountabilityVendor deploys signed with their CI identity, timestamped
    Compliance auditsExportable evidence bundle, offline verifiable
    Recognition Test

    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.

  • Chain head anchoring - External timestamping or signed checkpoints
  • GitOps controllers - Attestation at sync events
  • Terraform PR automation - Atlantis, Spacelift, env0
  • Policy engines - Gate deployments on attestation presence
  • Multi-cloud support - GCP KMS, Azure Key Vault

  • 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

  • KMS AWS KMS - HSM-backed signing. Private key never exported. Public key for offline verification.
  • S3 S3 Object Lock - WORM storage in COMPLIANCE mode. Provides WORM semantics commonly used in SEC 17a-4 contexts.
  • DDB DynamoDB - Chain state tracking. Stores previous hash for atomic linking.
  • Lambda Lambda - Serverless orchestration. Triggered on each deployment.
  • 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.

    awsterraformsecuritydevopsplatformforensicssupply-chainprovenanceattestationkmstamper-evident