- 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
| Technique | What it protects | Typical use | Limitations |
|---|---|---|---|
| Sensitive variables | Prevents values from appearing in CLI output and logs | Development and quick wins in any project | Does not prevent values from being saved to state |
Environment variables (TF_VAR_<name> and provider creds) | Keeps secrets out of .tf and .tfvars files and VCS | Local dev and CI with secret injection | Secrets read by Terraform may still be written to state |
| External secret stores (Vault, AWS Secrets Manager, Key Vault) | Centralized secrets, rotation, ACLs, audit logs | Production and audited systems | If Terraform reads secrets and writes plaintext into resources, state can still contain them; prefer secret references/ARNs |
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)
| Action | Why |
|---|---|
Mark inputs/outputs as sensitive | Avoid accidental printing in CLI output and logs |
Use TF_VAR_ or CI secret injection | Keep secrets out of .tf and .tfvars and out of VCS |
| Prefer secret references (ARNs/IDs) in resources | Prevents plaintext secrets from being stored in state |
| Use external secret managers for production | Centralized control, rotation, auditing |
| Secure remote state backend | Encrypt state at rest and enforce ACLs |
| Avoid passing secrets on the CLI | Command-line arguments can be visible to other processes/users |
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.