Terraform · Infrastructure as code

How do you design a safe Terraform CI/CD pipeline?

Hardci cdautomationoidcUpdated Oct 2026
Quiz this track

Short answer

A safe pipeline runs fmt, init, validate and plan on pull requests, then applies the saved plan after approval on the main branch. Use short-lived OIDC credentials, remote state locking and one concurrency group per environment.

The pipeline should make the plan the review artifact. Pull requests get a read-only plan and policy checks. Merges to main produce or reuse an approved plan and apply it with a role that can change infrastructure. Human review happens before the write credentials are used.

yaml
name: terraform
on:
  pull_request:
  push:
    branches: [main]

jobs:
  plan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9.8
      - run: terraform fmt -check -recursive
      - run: terraform init -input=false
      - run: terraform validate
      - run: terraform plan -input=false -out=tfplan
The plan job is read-only. A separate environment-protected job applies the saved artifact after approval.

Controls that matter

  • OIDC federation to a short-lived cloud role instead of stored keys
  • Remote state with locking and one workspace per environment
  • A concurrency group so two runs cannot apply to the same state
  • Plan artifacts tied to the commit and reviewed before apply
  • Protected environments and required reviewers for production

Separate read and write credentials. Plan only needs read access plus state locking; apply needs the write role. Store the plan artifact with limited retention and checksum it, and never download and apply a plan from an untrusted pull request.

Do not run apply from a laptop as the normal path. Local applies bypass approvals, audit trails and the concurrency controls the pipeline provides.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1How do you authenticate Terraform to AWS without static keys?
  2. 2Why apply a saved plan instead of re-planning in the apply job?
  3. 3How do you prevent two pipeline runs from applying at once?
  4. 4What permissions should the plan job have?

Say it in the interview

I split the pipeline into a read-only plan job on pull requests and a protected apply job on main. The plan is saved as an artifact, reviewed, then applied without re-planning. CI authenticates with OIDC to short-lived roles, uses remote state with locking, and has a concurrency group per environment. I never make a laptop apply the normal path, because that bypasses approvals and audit history.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Terraform mock interview and get scored feedback on depth, clarity and confidence.