Cloud & DevOps6 min read

Terraform Infrastructure as Code

Manage cloud infrastructure with Terraform: HCL modules, state management, workspace patterns, plan/apply workflow, and drift detection.

terraformiacinfrastructureaws

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

  1. Write basic Terraform configurationHCL declaratively defines resources - Terraform figures out how to create/update them.
  2. Configure remote state with S3 and lockingRemote state enables team collaboration and prevents concurrent apply races that corrupt state.
  3. Create reusable modulesModules encapsulate patterns (VPC, RDS, ECS) that multiple environments share.
  4. Manage multiple environments with workspacesWorkspaces allow the same code to manage multiple environments (dev/staging/prod) with separate state.
  5. 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/terraform
  • Terraform AWS provider: https://registry.terraform.io/providers/hashicorp/aws/
  • terraform-aws-modules: https://registry.terraform.io/namespaces/terraform-aws-modules
  • Atlantis: https://www.runatlantis.io/

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.