Terraform in CI/CD Pipelines
Production-level Terraform CI/CD: Code Commit → Validate → Format Check → Terraform Init → Plan → Policy Check (Sentinel/OPA) → Manual Approval → Apply. Remote state in S3 + DynamoDB lock. GitHub Actions flow, folder structure, and best practices for safe infrastructure automation.
Overview
Why Terraform needs a pipeline
Running Terraform manually is fine for experiments. In production without CI/CD there is no peer review, no audit trail, no policy enforcement and no protection against two people applying at once.
- Consistent — The same pipeline runs every time
- Collaborative — Changes are reviewed via PR
- Auditable — Full history in CI logs
- Safe — Policy gates and manual approval before Apply
The nine-step pipeline
- 1. Code commit — Engineer raises a PR with .tf changes
- 2. Validate — terraform validate checks syntax and references
- 3. Format check — terraform fmt -check fails if code is not formatted, enforcing one style
- 4. Init — Downloads providers and configures the backend (S3 remote state)
- 5. Plan — Shows exactly what will be created, modified or destroyed; uploaded as a CI artifact for reviewers
- 6. Policy/security check — Sentinel (enterprise), OPA (open source) or Checkov scans the plan: no public S3 buckets, instance type allowlist, tagging requirements
- 7. Manual approval — A human reviews the plan and policy results; the critical gate for production
- 8. Apply — Applies the exact plan artifact from step 5, avoiding drift between plan and apply
- 9. Production cloud — Resources are created or modified as planned
> [!IMPORTANT] Apply the saved plan from step 5, never a fresh one.
Remote state
terraform.tfstate is stored in S3, with S3 versioning for state recovery. A lock ensures only one operation modifies state at a time.
- S3 — Stores terraform.tfstate centrally; versioning allows recovery
- DynamoDB table — Classic state locking
- use_lockfile = true — Native S3 locking since Terraform 1.10; 1.11 deprecated dynamodb_table
Production folder structure
- modules/ — Reusable components: vpc, ec2, alb
- envs/dev, envs/prod — Environment-specific configurations calling modules
- backend.tf — S3 backend config
- provider.tf, variables.tf, outputs.tf, main.tf — Provider, inputs, outputs, resources
Key concepts
- terraform plan artifact
- The binary plan file generated by terraform plan -out=tfplan. Using this artifact in the Apply step guarantees exactly what was reviewed gets applied — no drift between plan and apply due to code changes or timing.
- DynamoDB state locking
- Terraform writes a lock entry to a DynamoDB table when it starts plan or apply. If another operation tries to run simultaneously, it sees the lock and fails with an error. Prevents race conditions in CI/CD and concurrent manual runs.
- Sentinel / OPA policy as code
- Policy engines that evaluate the Terraform plan against rules. Example rules: EC2 instances must be in the allowed_instance_types list, S3 buckets must have encryption enabled, all resources must have required tags. Violations fail the pipeline before Apply.
- Manual approval gate
- A required human review step in the pipeline between Plan and Apply. In GitHub Actions: environment protection rules with required reviewers. In GitLab CI: manual job trigger. Ensures a human eyes the plan before infrastructure is modified.
- Workspace vs environment folders
- Terraform Workspaces allow multiple state files per configuration (dev/staging/prod). Environment folders (envs/dev/, envs/prod/) are separate directories with separate backend configs — more explicit and easier to review. Both approaches are valid; environment folders are preferred for large teams.
- Checkov
- Open-source static analysis tool for Terraform and other IaC. Scans .tf files for security misconfigurations before plan (faster than Sentinel/OPA which operate on the plan). Run as a CI step: checkov -d . — fails on high/critical findings.
When to use it
- Any team running Terraform in production — manual apply is not acceptable at scale
- Meeting compliance requirements for infrastructure changes (SOC2, PCI-DSS require change control)
- Multi-engineer teams where two people could accidentally apply conflicting changes
- Organizations that need an audit trail of every infrastructure change
- Implementing GitOps for infrastructure — Terraform state follows Git as the source of truth
Interview questions
- How do you safely run Terraform in a CI/CD pipeline?
- Describe Terraform remote state with S3 and DynamoDB.
Sign up free to read the full topic
More DevOps topics
- Team Topologies
- Tekton
- Terraform — Production Errors, Mistakes and Recovery
- Terraform & OpenTofu
- Terraform count vs for_each
- Terraform Essentials — Plan and Apply, Variables, Outputs, Data Sources, and Sharing State at Scale
- Terraform Remote State — S3 + DynamoDB
- Test Pyramid
- The C/C++ Compilation Model
- The flux CLI
- The Three Ways
- Toil Reduction & Automation Strategy
Start free on Cariara · Coding problems · System design studio