By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
(For Engineers Who Need to Ship Secure IaC—Fast)
You’re deploying a Terraform stack that needs a database password, an API key, or a TLS certificate. If you hardcode these in plaintext, you just turned your Git repo into a treasure map for attackers. Even if you delete the secret later, Git history keeps it forever.
Why this matters in production:- Compliance violations: PCI-DSS, HIPAA, SOC2, and GDPR all require secrets to be encrypted at rest and in transit.- Security breaches: A leaked AWS secret key can cost $100K+ in stolen resources (or ransomware).- Operational chaos: Rotating a leaked secret means downtime, manual updates, and firefighting.
Real-world scenario:You inherit a Terraform repo where terraform.tfvars contains:
terraform.tfvars
db_password = "SuperSecret123!"
This file is committed to Git. Your first task: Secure this immediately—without breaking the deployment.
sensitive = true
variables.tf
TF_VAR_
TF_VAR_db_password
ps aux
aws_secretsmanager_secret_version
aws_ssm_parameter
terraform apply
sensitive
remote-exec
local-exec
terraform state
>= 0.14
aws configure
Deploy an RDS MySQL instance with a password fetched from AWS Secrets Manager (not hardcoded).
# Create a secret (replace with your password) aws secretsmanager create-secret \ --name "prod/db/password" \ --secret-string "SuperSecret123!" \ --description "RDS MySQL root password"
Verify:
aws secretsmanager get-secret-value --secret-id "prod/db/password"
main.tf
provider "aws" { region = "us-east-1" } # Fetch the secret from AWS Secrets Manager data "aws_secretsmanager_secret_version" "db_password" { secret_id = "prod/db/password" } # Create RDS instance with the secret resource "aws_db_instance" "mysql" { allocated_storage = 20 engine = "mysql" engine_version = "8.0" instance_class = "db.t3.micro" db_name = "mydb" username = "admin" password = data.aws_secretsmanager_secret_version.db_password.secret_string parameter_group_name = "default.mysql8.0" skip_final_snapshot = true publicly_accessible = false # ⚠️ Critical for security! } # Output the RDS endpoint (mark as sensitive) output "rds_endpoint" { value = aws_db_instance.mysql.endpoint sensitive = true }
variable "region" { description = "AWS region" default = "us-east-1" }
terraform init terraform plan # Verify the secret is fetched (but not shown in logs) terraform apply -auto-approve
Expected output:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed. Outputs: rds_endpoint = <sensitive>
bash terraform show -json | jq '.values.root_module.resources[] | select(.address == "aws_db_instance.mysql")'
⚠️ The password is still in plaintext in the state file! (We’ll fix this in Best Practices.)
Check AWS Console:
hcl terraform { backend "s3" { bucket = "my-terraform-state" key = "prod/terraform.tfstate" region = "us-east-1" encrypt = true kms_key_id = "alias/terraform-state-key" } }
json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/db/*" } ] }
hcl resource "aws_secretsmanager_secret" "db_password" { name = "prod/db/password" description = "RDS MySQL root password" tags = { Environment = "prod" Owner = "devops-team" } }
bash aws cloudtrail create-trail --name SecretsManagerTrail --s3-bucket-name my-cloudtrail-logs
GetSecretValue
*.tfvars
.gitignore
user_data
Answer: Mark the output as sensitive = true and use a secrets manager (e.g., AWS Secrets Manager).
Trick Question: "Is marking a variable as sensitive = true enough to secure it?"
Answer: No. It only hides the value from logs—it’s still in plaintext in the state file.
Scenario: "Your Terraform state file contains secrets. How do you secure it?"
Deploy an EC2 instance with an SSH key fetched from AWS Secrets Manager (instead of a hardcoded key pair).
Requirements:1. Store the private key in AWS Secrets Manager.2. Fetch the key during terraform apply.3. Inject the key into the EC2 instance via user_data.
Solution:
data "aws_secretsmanager_secret_version" "ssh_key" { secret_id = "prod/ec2/ssh_key" } resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 instance_type = "t3.micro" user_data = <<-EOF #!/bin/bash echo "${data.aws_secretsmanager_secret_version.ssh_key.secret_string}" > /home/ec2-user/.ssh/id_rsa chmod 600 /home/ec2-user/.ssh/id_rsa EOF }
Why it works:- The key is fetched at runtime (not hardcoded).- user_data writes the key to the instance (but ⚠️ this is still visible in instance metadata—use SSM Parameter Store for better security).
output "db_password" { value = var.password, sensitive = true }
export TF_VAR_db_password="SuperSecret123!"
aws ssm get-parameter --name "/prod/db/password" --with-decryption
vault kv get -mount=secret prod/db/password
terraform { backend "s3" { encrypt = true, kms_key_id = "..." } }
*.auto.tfvars
connection { private_key = file("~/.ssh/id_rsa") }
Final Pro Tip:
"Treat your Terraform state file like a nuclear launch code. Encrypt it, restrict access, and never commit it to Git. A single leaked state file can compromise your entire infrastructure."
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.