interview-prep

Crisp answer: Mark values as sensitive using the sensitive type modifier or the sensitive argument on outputs and variables. Sensitive values are redacted in plan and apply output but are stored in plaintext in the state file.

Marking a variable as sensitive:

variable "db_password" {
  type      = string
  sensitive = true
}
terraform plan
# ~ aws_db_instance.main
#   password = (sensitive value)   ← redacted in output

Marking an output as sensitive:

output "connection_string" {
  value     = "postgres://app:${aws_db_instance.main.password}@${aws_db_instance.main.endpoint}/mydb"
  sensitive = true
}
terraform output connection_string
# (sensitive value)

terraform output -raw connection_string
# postgres://app:secret123@db.eu-west-2.rds.amazonaws.com/mydb
# ← -raw bypasses redaction in CLI (intentional — you asked for it)

The sensitive() function:

Mark any value as sensitive programmatically:

locals {
  connection_string = sensitive(
    "postgres://${var.db_user}:${var.db_password}@${aws_db_instance.main.endpoint}/${var.db_name}"
  )
}

The state file problem:

Sensitive values are redacted in terminal output but NOT in the state file. Anyone with read access to the state file can extract them:

cat terraform.tfstate | python3 -m json.tool | grep password
# "password": "secret123"   ← plaintext in state

This is why state files must be:

  • Stored in an encrypted S3 bucket (SSE-S3 or SSE-KMS)
  • Access-controlled via S3 bucket policies and IAM
  • Never committed to version control

Best practices for actually sensitive values:

# Use AWS-managed secrets where the provider supports it
resource "aws_rds_cluster" "main" {
  manage_master_user_password = true   # Password never enters Terraform state
}

# Use external secret references instead of the secret value itself
data "aws_secretsmanager_secret_version" "db" {
  secret_id = "prod/db/password"       # Only the path is in config
}
# The value is still in state but at least it's not hardcoded in config

What to say in the interview:

"Sensitive marks values as redacted in terminal output, which prevents them appearing in CI logs. But sensitive does not protect values in the state file — they are stored plaintext. This is the key limitation. The real solution is avoiding sensitive values in state altogether: use the manage_master_user_password flag for RDS so AWS generates and stores the password in Secrets Manager without it passing through Terraform, and ensure the state backend is encrypted and access-controlled. Sensitive is a display hint, not actual security."

My notes