Skip to main content
Storing secrets (database passwords, API keys, tokens) directly in Terraform files is a risky and common mistake. This guide explains why you should avoid committing secrets to version control and shows how to use environment variables (and CI/CD secret stores) safely with Terraform.
Never commit files that contain secrets (for example, terraform.tfvars) to your repository. Use environment variables or a secrets manager instead.

Why committing secrets is dangerous

Committing secrets to Git makes them part of the repository history. Even if you delete the file later, the secret remains in the history and requires rewriting history (e.g., git filter-repo or BFG) to remove. Leaked credentials are commonly discovered by security scanners and attackers scanning public or shared repos. Bad example — secrets in terraform.tfvars:
Instead, supply secrets at runtime using environment variables so they are not stored in source files.

Use environment variables with Terraform (TF_VAR_<name>)

Terraform supports mapping environment variables that follow the TF_VAR_<variable_name> pattern to input variables. Set environment variables in your shell or CI job and Terraform will use them when evaluating var.<name>. Local shell example:
Define the Terraform variable without a default and mark it sensitive:
When you run terraform apply, Terraform reads TF_VAR_db_password and uses it for var.db_password. This avoids writing secrets to disk and lowers the chance of accidental commits.
A presentation slide titled "Benefits of Using Environment Variables" showing four callouts: "Never stored in files," "Never committed to git," "Perfect for CI/CD pipelines," and "Works with sensitive = true." The background shows people working at laptops and monitors in an office.

Important caveat: Terraform state may contain secrets

Environment variables prevent secrets from being stored in your repo files, but they do not prevent secret values from being written into Terraform state. Protect state with remote backends, encryption, access controls, and state locking.
When Terraform creates resources, secret attributes (for example, DB passwords or API keys returned by providers) can be written into the state file. Use remote state backends (S3 with server-side encryption, Terraform Cloud, etc.), enable access controls, and enable state locking to reduce risk.

Using environment variables in CI/CD (GitHub Actions example)

Store secrets in your CI/CD platform’s secret storage and inject them as environment variables at runtime. GitHub Secrets, for example, decrypt secrets only during the job run. Example GitHub Actions job:
Notes about CI/CD secrets:
  • CI systems encrypt secrets at rest and inject them only at runtime.
  • Avoid echoing or saving secrets to disk in the job; do not print them to logs.
  • CI providers typically redact secrets from logs but never rely solely on redaction.

Secret storage options at a glance

Best practices checklist

  • Do not commit terraform.tfvars or files with secrets; add them to .gitignore.
  • Use TF_VAR_<name> environment variables or CI secret injection for Terraform inputs.
  • Mark sensitive Terraform variables with sensitive = true to avoid printing them.
  • Protect Terraform state: use a remote backend, encryption, access control, and locking.
  • Prefer dedicated secret managers (Vault, AWS Secrets Manager) for production workloads and rotate secrets regularly.
  • Never print secrets in CI logs or store them in plaintext in scripts or artifacts.

References and further reading

This approach — inject secrets as environment variables at runtime, mark variables sensitive in Terraform, and protect state with a secure backend — gives you a practical, production-ready workflow for keeping secrets out of version control.

Watch Video