Infrastructure as Code (IaC) — Automating with Terraform

A practical overview of Terraform-driven IaC: organizing modules, managing state, and creating reproducible infrastructure deployments.

Key concepts

  • Modules for reuse and encapsulation
  • State management and remote backends (S3, GCS)
  • Workspaces, CI-driven plans and apply gates
  • Drift detection and policy-as-code (Sentinel, OPA)
Git Repo (modules & envs) .tf, modules/, env/*.tfvars CI/CD Runner terraform init/plan/apply Remote Backend S3/GCS + State Lock (DynamoDB) Workspaces for envs / tenant

Figure: store Terraform in Git, run plan/apply in CI, keep state in a remote backend with locking and use workspaces for environment isolation.

Terraform module example

Keep reusable components as modules. Example: simple VPC/network module (modules/network/main.tf).

// modules/network/main.tf
variable "name" {}
variable "cidr" { default = "10.0.0.0/16" }

resource "aws_vpc" "this" {
  cidr_block = var.cidr
  tags = { Name = var.name }
}

output "vpc_id" { value = aws_vpc.this.id }

Root module usage

module "network" {
  source = "./modules/network"
  name   = "prod-vpc"
  cidr   = "10.1.0.0/16"
}

Remote backend example (S3 + DynamoDB locking)

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "envs/prod/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}

Workspaces & variable files

Use workspaces or one directory per environment. Keep secrets out of version control and supply via secure variable sources (Vault, cloud secrets).

# recommended workflow
terraform workspace new prod
terraform init
terraform plan -var-file=env/prod.tfvars
terraform apply -var-file=env/prod.tfvars

CI integration (GitHub Actions example)

Run plan on PRs and apply only after approvals or merging to main/production branch.

name: Terraform
on:
  pull_request:
  push:
    branches: [ main ]

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: hashicorp/setup-terraform@v2
      - name: Terraform Init
        run: terraform init
      - name: Terraform Format
        run: terraform fmt -check
      - name: Terraform Plan
        run: terraform plan -var-file=env/${{ github.ref_name }}.tfvars
      - name: Upload plan artifact
        if: github.event_name == 'pull_request'
        uses: actions/upload-artifact@v3
        with:
          name: tfplan
          path: plan.out

Best practices & notes

  • Use modules to encapsulate reusable infra patterns.
  • Store state remotely with encryption and locking to avoid concurrent applies.
  • Run plan in CI and gate apply via approvals, protected branches or automation with least privilege.
  • Use policy-as-code (OPA/Sentinel) to enforce guardrails before apply.

Conclusion

Use Terraform modules, remote state with locking, and automated plan/apply in CI to maintain stable, auditable infrastructure across environments. Treat state carefully, secure secrets, and adopt policy-as-code to prevent risky changes.