Terraform Advanced — Security Exercises

less than 1 minute read

Practice security hardening for Terraform.


Exercise 1 — Sensitive Variable

Task: Declare a variable for a database password that won’t appear in plan output.

Answer
variable "db_password" {
  type        = string
  description = "Database master password"
  sensitive   = true
}

Pass it via environment variable:

export TF_VAR_db_password="my-secret-pass"
terraform apply

Exercise 2 — OPA Policy

Task: Write a Rego policy that denies EC2 instances without encrypted root volumes.

Answer
package main

deny[msg] {
    resource := input.resource_changes[_]
    resource.type == "aws_instance"
    block := resource.change.after.root_block_device[_]
    not block.encrypted
    msg := sprintf("Instance '%s' must have encrypted root volume",
                   [resource.name])
}

Exercise 3 — Dynamic Secrets

Task: Write Terraform config to read a database password from AWS Secrets Manager instead of hardcoding it.

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

resource "aws_db_instance" "main" {
  engine   = "postgres"
  username = "admin"
  password = data.aws_secretsmanager_secret_version.db_password.secret_string
}

Chapter Summary

  • Mark sensitive variables with sensitive = true
  • Use Secrets Manager or Vault — never hardcode secrets
  • Vault provides dynamic, short-lived credentials
  • Sentinel (TF Cloud) or OPA/Conftest (open source) for policy enforcement
  • Apply least-privilege IAM — use iamlive to discover minimal permissions
  • Always encrypt state at rest and in transit

← Least Privilege IAM Chapter 12: Multi-Cloud →

Updated: