The "Open Secret"
This is the most critical security concept in Terraform state management: state files are stored as plain text JSON, regardless of whether you mark variables as sensitive.
Consider a database resource whose password comes from a variable explicitly marked sensitive = true. After terraform apply, the state file's JSON still contains that password attribute as a plain, readable string, sitting right next to the username — the sensitive flag never touched the state file at all. The sensitive = true flag on a variable only suppresses the value in Terraform's terminal output. It does nothing to protect the value in the state file.
Mitigation Strategies
Because of this hard truth, you must treat your state files as highly sensitive artifacts — equivalent to a secrets vault.
1. Encryption at Rest
Always configure your remote backend to use server-side encryption. For S3, this means enabling SSE-S3 or SSE-KMS on the bucket. For GCS, enable CMEK (Customer-Managed Encryption Keys). Encryption at rest protects against someone gaining physical access to the storage medium, but does not protect against someone with IAM access to the bucket.
2. Strict Access Control
Use IAM policies to enforce least-privilege access to the state bucket, explicitly denying read access to everyone except the specific roles that legitimately need it:
- The CI/CD system needs read/write access to run plan and apply.
- Senior platform engineers may need read access for debugging.
- Application developers generally should NOT have direct read access to production state files.
3. External Secrets Management
The most robust approach is to keep secrets out of Terraform state entirely. Instead of having Terraform set the database password, create the database with a temporary placeholder password, then use AWS Secrets Manager or HashiCorp Vault to manage the actual password outside of Terraform — Terraform creates the secret's placeholder entry, but a separate rotation process (not Terraform) sets and rotates its real value, so the real password never appears in state at all.
4. State Versioning
Enable versioning on your S3 state bucket. If state becomes corrupted or a bad apply destroys resources unexpectedly, you can roll back to a previous version of the state file and use it as a recovery starting point.
Restore a specific version
aws s3api copy-object \
--bucket my-company-tfstate \
--copy-source "my-company-tfstate/prod/app/terraform.tfstate?versionId=abc123" \
--key prod/app/terraform.tfstate
```
Interviewers frequently ask: "How do you handle secrets in Terraform?" A weak answer is "I use sensitive variables." A strong answer acknowledges that sensitive = true only hides values in terminal output — the values still appear in plain text in the state file. The correct approach is a combination of: (1) encrypting the state bucket at rest, (2) strict IAM access controls on the state bucket, and (3) ideally, keeping secrets out of Terraform state entirely by using external secrets managers like AWS Secrets Manager or Vault, with Terraform only creating the secret resource shell and a separate rotation process managing the actual value.
Key Point: There is no way to fully encrypt sensitive values within the Terraform state file itself using open-source Terraform. The state file is always plain text JSON. HCP Terraform (HashiCorp's managed service) encrypts state at rest and in transit and provides fine-grained access controls, which is one of its primary value propositions over self-managed remote backends. If your organization handles highly sensitive data (PCI, HIPAA), this is a meaningful architectural consideration.