Terraform Infrastructure as Code
Manage cloud infrastructure with Terraform: HCL modules, state management, workspace patterns, plan/apply workflow, and drift detection.
Terraform is the dominant Infrastructure as Code tool - declarative HCL defines the desired state, Terraform creates/updates/destroys resources to match. It supports AWS, GCP, Azure, and 3000+ providers. Production use requires remote state, locking, and module reuse.
Use Terraform for all cloud infrastructure - avoid clicking in the console. Store state in S3 with DynamoDB locking. Modularize reusable patterns (VPC, ECS cluster). Run `terraform plan` in CI, `terraform apply` only on main branch. Use `terraform import` to bring in existing resources.
Workflow
- Write basic Terraform configurationHCL declaratively defines resources - Terraform figures out how to create/update them.
- Configure remote state with S3 and lockingRemote state enables team collaboration and prevents concurrent apply races that corrupt state.
- Create reusable modulesModules encapsulate patterns (VPC, RDS, ECS) that multiple environments share.
- Manage multiple environments with workspacesWorkspaces allow the same code to manage multiple environments (dev/staging/prod) with separate state.
- Set up CI/CD for TerraformAutomated plan/apply prevents manual errors and enforces review of infrastructure changes.
Output Format
HCL resources with variables and outputs, S3 backend with DynamoDB lock, reusable modules, workspace-based environments, `terraform plan` in CI + `apply` on merge.
Examples
RDS module: `resource "aws_db_instance" "main" { identifier = "${var.name}-db" engine = "postgres" engine_version = "16" instance_class = var.instance_class allocated_storage = var.storage username = var.db_username password = random_password.db.result db_subnet_group_name = var.subnet_group_name vpc_security_group_ids = [aws_security_group.db.id] skip_final_snapshot = var.environment != "prod" }`OIDC auth (no static keys): `data "aws_iam_openid_connect_provider" "github" { url = "https://token.actions.githubusercontent.com" }; resource "aws_iam_role" "github_actions" { assume_role_policy = jsonencode({ Statement = [{ Effect = "Allow", Principal = { Federated = data.aws_iam_openid_connect_provider.github.arn }, Action = "sts:AssumeRoleWithWebIdentity", Condition = { StringLike = { "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:*" } } }] }) }`Workspace values: `locals { config = { dev = { min_capacity = 1, max_capacity = 2 }, prod = { min_capacity = 3, max_capacity = 20 } }[terraform.workspace] }`Edge Cases & Gotchas
- State file secrets: Terraform state may contain sensitive values (passwords, keys) in plaintext. Encrypt the S3 bucket, use KMS, and restrict IAM access to the state bucket
- Resource recreation: some changes force recreation (`ForceNew` in provider code). Always review plan carefully - `aws_db_instance` recreation deletes the database unless `skip_final_snapshot = false`
- Dependency cycles: Terraform infers dependencies from references. Circular dependencies cause errors - break the cycle by using data sources or splitting into separate modules
When to Break These Rules
- For AWS-only infrastructure, CDK (Cloud Development Kit) or Pulumi offer typed programming language interfaces instead of HCL - better for complex logic (loops, conditionals, dynamic configurations).
Reference Files
Terraform docs: https://developer.hashicorp.com/terraformTerraform AWS provider: https://registry.terraform.io/providers/hashicorp/aws/terraform-aws-modules: https://registry.terraform.io/namespaces/terraform-aws-modulesAtlantis: https://www.runatlantis.io/