Table of Contents

The Problem With Secrets in Terraform

Terraform state files contain sensitive data in plain text. API keys, database passwords, and certificates stored in state are readable by anyone with state access. Here’s how to handle this securely.

Rule 1: Never Hardcode Secrets

# BAD - secret in code
resource "aws_db_instance" "db" {
  password = "super-secret-password"  # This ends up in state AND git
}

# GOOD - use a variable
resource "aws_db_instance" "db" {
  password = var.db_password
}

Method 1: Environment Variables

export TF_VAR_db_password="super-secret-password"
terraform apply

Method 2: AWS Secrets Manager

data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = "prod/database/password"
}

resource "aws_db_instance" "db" {
  password = data.aws_secretsmanager_secret_version.db_password.secret_string
}

Method 3: HashiCorp Vault

provider "vault" {
  address = "https://vault.example.com"
}

data "vault_generic_secret" "db" {
  path = "secret/data/prod/database"
}

resource "aws_db_instance" "db" {
  password = data.vault_generic_secret.db.data["password"]
}

Method 4: SOPS Encrypted Files

# Encrypt a tfvars file
sops --encrypt --in-place secrets.tfvars

# Decrypt and apply
sops -d secrets.tfvars | terraform apply -var-file=/dev/stdin

Marking Outputs as Sensitive

output "db_connection_string" {
  value     = "postgresql://${var.db_user}:${var.db_password}@${aws_db_instance.db.endpoint}"
  sensitive = true
}

variable "db_password" {
  type      = string
  sensitive = true  # Prevents value from showing in plan output
}

State File Security

Even with these methods, sensitive values still exist in state. Protect state by:

  1. Encrypting state at rest — enable S3 SSE or use encrypted backends
  2. Restricting state access — IAM policies limiting who can read state
  3. Using Terraform Cloud — state is encrypted and access-controlled
  4. Never committing state to git — add *.tfstate to .gitignore

Best Practices Summary

  1. Never hardcode secrets in .tf files
  2. Use a secrets manager (AWS SM, Vault, Azure Key Vault)
  3. Mark sensitive variables and outputs with sensitive = true
  4. Encrypt state at rest and restrict access
  5. Rotate secrets regularly
  6. Use short-lived credentials (OIDC, STS) where possible

Learn More