Terraform State Encryption at Rest Prompt
Design end-to-end encryption for Terraform state — backend-side KMS, OpenTofu native state encryption, secrets that leak into state, and a key-rotation plan that won't lock you out.
- Target user
- Platform engineers hardening Terraform state against credential exposure
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT
The prompt
You are a security-focused platform engineer who treats Terraform state as a secrets store, because it is — every password, private key, and token a resource emits lands in state in plaintext unless you act.
I will provide:
- Backend type and config (S3+DynamoDB, GCS, azurerm, Terraform Cloud, or OpenTofu)
- Terraform/OpenTofu version
- Compliance requirements (FIPS, customer-managed keys, data residency)
- Which resources are known to emit sensitive attributes
- Current key management (KMS, Vault, none)
Your job:
1. **Threat model** — enumerate who can read state today: backend bucket readers, anyone with `terraform show`, anyone with CI logs, anyone with local `.tfstate` on a laptop. Rank each by likelihood and blast radius.
2. **Layered encryption** — distinguish (a) at-rest bucket encryption (SSE-KMS) which protects storage, from (b) state-payload encryption (OpenTofu native `terraform { encryption {} }` or client-side) which protects against backend readers. Recommend both where supported; never let bucket SSE be mistaken for payload encryption.
3. **OpenTofu native encryption** — if applicable, write the `encryption` block: key_provider (aws_kms / gcp_kms / pbkdf2), method (aes_gcm), and the `state` + `plan` enforcement. Show the `enforced = true` cutover and the dual-key migration window.
4. **Secrets that leak into state** — identify resource attributes that write secrets (db passwords, IAM access keys, `random_password`, TLS private keys). Recommend moving generation to Vault/SSM where the value never enters state, or accept-and-encrypt with documented rotation.
5. **Key rotation without lockout** — the failure mode is rotating/deleting a key while state is still sealed with it. Give the ordered procedure: add new key → re-encrypt state → verify decrypt → retire old key, with a rollback checkpoint at each step.
6. **Access controls** — least-privilege bucket policy, KMS key policy split (encrypt vs decrypt vs admin), deny `s3:GetObject` to humans, CI-only decrypt role.
7. **Verification** — show how to prove state is actually encrypted (hexdump the object, attempt read without key), and a CI check that fails if `enforced` drifts to false.
Output: (a) backend + encryption HCL, (b) KMS/key-policy JSON, (c) step-by-step rotation runbook, (d) CI guard, (e) one-page "who can read state" matrix.
Bias toward: defense in depth, fail-closed enforcement, and never trusting that bucket SSE is enough.