The common mistake
A common pattern: you create a resource that needs a password (for example, a database), so you put that password into a Terraform variable and continue. It seems convenient, but that value will often appear in multiple places across your Terraform workflow—and frequently as plain text. Treating Terraform variables like a secret vault is a mistake.Terraform state and why secrets appear
Terraform persists a complete representation of the infrastructure it manages. “Complete” includes resource attributes that are necessary for lifecycle operations and drift detection—sensitive values such as passwords, API keys, and connection strings included. By default Terraform state is serialized as JSON (plain text). If you use a shared backend (remote state), anyone with access to the backend can potentially read those secrets. CI/CD systems can also capture Terraform output or provider error messages in logs, which may expose sensitive values. Warning: Terraform stores secrets in state by design to perform its management tasks. The correct approach is to protect state and other exposure points, not to expect Terraform to avoid storing needed attributes.Example state snippet
Below is a representative excerpt from a local Terraform state file showing how a database password can appear in multiple places:Where secrets can end up
Secrets in a Terraform workflow commonly surface in four places. The table below summarizes each exposure point and why it is risky:| Exposure point | Why it’s risky | Typical examples |
|---|---|---|
| State files | State contains full resource attributes in JSON, including secrets | terraform.tfstate, remote backend state |
| Logs & console output | terraform plan, terraform apply, provider errors, and CI logs can reveal values | Terminal output, CI job logs |
| Version control | Committed .tfvars or hard-coded credentials become part of Git history | terraform.tfvars, inline secrets in .tf files |
| Plan artifacts | Saved terraform plan files and similar artifacts include proposed values | CI artifacts, stored plans |

Multiple exposure points require layered protections
Because secrets may appear in state, logs, version control, and artifact storage, apply defenses in depth:- Protect state
- Use secure remote backends that support encryption at rest and strong access controls.
- Enable backend locking where available to prevent concurrent writes.
- Limit who and what (CI jobs, agents) can access the state backend.
- Avoid leaking secrets in logs and CI
- Use
sensitive = truefor variables and outputs to reduce accidental CLI exposure (note: this does not prevent secrets from being stored in state). - Sanitize provider outputs and minimize verbose logging in CI.
- Treat CI logs as sensitive artifacts and rotate tokens/keys used in CI.
- Use
- Keep secrets out of version control
- Never commit
terraform.tfvarswith real secrets or hard-code credentials in.tffiles. - Use pre-commit hooks and secret-scanning tools to detect accidental commits.
- Never commit
- Manage plan artifacts carefully
- Avoid storing plans with sensitive values in long-lived or public artifact repositories.
- If you must store artifacts, ensure they are encrypted and access is restricted.
What this section will cover
In the upcoming lessons we will present specific, practical techniques to reduce the exposure of secrets across Terraform workflows:- Using sensitive variables and environment variables to prevent casual CLI exposure and to reduce the chance of committing credentials. Keep in mind that marking a variable as
sensitivewill not stop Terraform from persisting its value in state if the provider requires it. - Encrypting and protecting state backends, enforcing least privilege, and configuring backend access controls.
- Leveraging provider-specific features that can avoid writing secrets into state when providers offer them (for example, providers that return ephemeral credentials or avoid storing generated secrets).
- Integrating external secrets managers (for example, learn more in the Vault Associate Certification course) so sensitive values are retrieved dynamically and not committed to Terraform state. We’ll also cover workflow design to avoid persisting fetched secrets in state if that’s not acceptable for your security posture.
Understand where secrets will appear in your workflow first; then apply protections to each layer (state, logs, VCS, and artifacts).