- Sensitive variables — quick wins that hide values from CLI output and logs.
- Environment variables — keep secrets out of your repository and
.tfvars. - External secret stores — the recommended approach for production.
Why this matters
Terraform often stores resource attributes (including secrets) in the state. Even when values are redacted from CLI output, the state may still contain plaintext secrets. Treat your state like any other sensitive datastore: use remote backends with encryption and strict access control.Overview: techniques at a glance
1) Sensitive variables
Marking variables and outputs assensitive tells Terraform to redact those values from CLI output and logs. This is the fastest, lowest-effort change that reduces accidental exposure.
Example variable definition (variables.tf):
main.tf):
outputs.tf):
Marking variables or outputs as
sensitive hides them from CLI output and logs but does not remove values from the Terraform state. Always secure your state (use a remote backend with encryption and access controls).2) Environment variables
Environment variables let you inject secrets without writing them into.tf or .tfvars, preventing accidental commits.
- Use the
TF_VAR_<name>convention to set input variables from the environment. - Provider credentials (for example
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,VAULT_TOKEN) are commonly passed via environment variables and are supported by most providers.
- Prefer CI/CD secret stores or OS-level secret managers to inject variables for automated runs.
- Avoid passing secrets via
terraform apply -var 'db_password=...'if process-list exposure is a concern. - Use ephemeral shells and short-lived credentials where possible.
- Remember: if Terraform writes the secret to a resource attribute, the value may still be captured in state.
3) External secret stores (recommended for production)
For production systems, use a dedicated secrets manager for centralized secret lifecycle management, auditing, and rotation. Options include HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, and Google Secret Manager. Two common patterns:- Read secret values at apply time and pass them into resources (convenient but may store plaintext in state).
- Configure resources with secret references/IDs (preferred) so Terraform only stores identifiers (ARNs/IDs) instead of plaintext secrets.
- AWS Secrets Manager (reading the secret at apply-time):
- HashiCorp Vault (Vault provider data source):
- If Terraform reads a secret and writes the plaintext into a resource attribute, the plaintext can end up in state. To avoid this, prefer APIs that accept secret references (for example, pass a Secrets Manager ARN or Key Vault secret reference).
- Design infrastructure to use secret references/IDs where possible so Terraform stores only identifiers.
- Enforce least privilege, short-lived credentials, rotation policies, and audit logging on your secret manager.
- Secure any provider tokens used to read secrets (store them in CI secret stores or encrypted environment variables).
Recommended practices (short checklist)
Quick reference: do’s and don’ts
- Do: mark inputs/outputs as
sensitiveto reduce accidental exposure in logs. - Do: inject secrets via environment variables or CI/CD secret stores rather than committing them.
- Do: use external secret managers in production and prefer passing secret references (ARNs/IDs) to resources.
- Do: secure your Terraform state with a remote backend, encryption, and strict access controls.
- Don’t: hardcode secrets in
.tfor.tfvarsthat are committed to version control. - Don’t: pass secrets on the
terraformcommand line if process-list leakage is a concern. - Don’t: assume
sensitiveprevents secrets from being stored in state—treat state as sensitive.
Best practice summary:
- Use
sensitivefor variables and outputs to avoid CLI leaks. - Prefer environment variable injection for development and CI.
- Use a secrets manager for production and pass secret references (ARNs/IDs) when possible.
- Always protect and monitor your Terraform state backend.
Closing
These three approaches are complementary. In real projects you’ll often:- Mark variables and outputs
sensitiveto reduce accidental exposure. - Use environment variables or CI secret injection for development and automated pipelines.
- Rely on a dedicated secret manager in production—prefer secret references so Terraform does not store plaintext secrets in state.