Module 15, Secrets Management
Why Variables Aren't Enough
# WRONG, the password ends up in terraform.tfstate in plaintext
variable "db_password" {
default = "SecurePass123!"
}
Anyone with access to the state file has your database password. State is often stored in S3 where access may be broader than intended.
AWS Secrets Manager
resource "aws_secretsmanager_secret" "db_password" {
name = "${var.app_name}/db-password"
recovery_window_in_days = 0 # immediate deletion (dev only; use 7+ for prod)
}
resource "aws_secretsmanager_secret_version" "db_password" {
secret_id = aws_secretsmanager_secret.db_password.id
secret_string = var.db_password
}
# Use AWS-managed rotation to avoid storing password in state entirely
resource "aws_db_instance" "main" {
manage_master_user_password = true # AWS handles rotation automatically
lifecycle { ignore_changes = [password] }
}
AWS Parameter Store
Cheaper than Secrets Manager for non-rotating config values:
resource "aws_ssm_parameter" "jwt_secret" {
name = "/${var.app_name}/${var.environment}/jwt-secret"
type = "SecureString" # KMS-encrypted
value = var.jwt_secret
}
# Read in application at runtime
data "aws_ssm_parameter" "jwt_secret" {
name = "/${var.app_name}/${var.environment}/jwt-secret"
with_decryption = true
}
Secrets Manager vs Parameter Store
| Feature | Secrets Manager | Parameter Store |
|---|---|---|
| Cost | ~$0.40/secret/month | Free (Standard tier) |
| Automatic rotation | ✅ Built-in | ❌ Manual |
| Versioning | ✅ | ✅ |
| Cross-account | ✅ | Limited |
| Best for | DB passwords, API keys | Config values, feature flags |
Knowledge Check
- Why does storing passwords in Terraform variables not fully solve the secrets problem?
- What is the difference between Secrets Manager and Parameter Store?
- What does
manage_master_user_password = truedo on an RDS instance? - How would you rotate a secret automatically?
- Why use
SecureStringtype in Parameter Store?