Automated Terraform Plan/Apply in CI/CD Pipeline Setup

Infrastructure code exists, but Terraform is run manually from an engineer's laptop, and state is stored locally — leading to drift, conflicts, and unplanned downtime. We automate Terraform Plan/Apply in CI/CD: setting up pipelines, remote state, and secure access via OIDC. Our team delivers the project turnkey — from audit to implementation with ongoing support.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Automated Terraform Plan/Apply in CI/CD Pipeline Setup

Terraform is run manually from an engineer's laptop — a classic situation in teams where infrastructure code exists but processes around it are unestablished. The problem isn't just unreliability (though that too). The issue is that terraform.tfstate lives on someone's computer, apply can be run without review, and the infrastructure change history is the git history of one person who commits "once a week when I remember." This practice leads to state drift, lock conflicts, and unplanned downtime. According to HashiCorp, automating plan/apply reduces MTTR by 70%.

Over 7+ years and 50+ projects, we've developed an approach that turns chaos into a manageable process. Integrating Terraform into CI/CD automates plan on every PR, apply after approval, and provides a full history in the pipeline. Below is a proven scheme with remote state, auto-comments, and OIDC security. Get in touch for an audit of your IaC — we'll assess your project and scope the work.

Why Integrate Terraform into CI/CD?

Manual infrastructure management is a direct path to state drift and human error. An automated pipeline guarantees:

  • Code review before every apply — changes visible to the whole team.
  • State stored in a central remote backend — no conflicts or loss.
  • Full change history: who, when, and what changed.
  • Apply only after a successful plan check — protection against accidental breakage.

Experience shows: switching to GitOps and CI/CD for Terraform reduces deployment time by 60% and reduces incident risk by 3 times compared to the manual approach.

Architecture: Where to Store State and How to Work with Workspaces

Before setting up CI/CD, you need to address remote state. S3 + DynamoDB for AWS, GCS for GCP, Azure Blob for Azure, or Terraform Cloud. Local state in CI is an antipattern — it dies with the runner. According to official Terraform documentation, remote state with locking is mandatory for team collaboration.

Example backend.tf configuration
# backend.tf
terraform {
  backend "s3" {
    bucket         = "mycompany-terraform-state"
    key            = "production/main.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}

dynamodb_table for State Locking is critical. Without locking, two concurrent terraform apply (e.g., two PRs merged simultaneously) can lead to corrupt state or conflicting infrastructure changes.

How to Protect the Production Environment During Automatic Apply?

Key principle — two-stage scheme: plan automatically, apply manually with production rights. We add when: manual to the apply stage and use environment: production for access separation. Additionally, RBAC in GitLab/GitHub is configured so only certain users can confirm apply.

For critical changes (resource deletion), you can add approval rules — for example, request a separate approval from the team lead.

Pipeline: Plan on PR, Apply After Merge

Standard two-stage scheme with validate:

# .gitlab-ci.yml
stages:
  - validate
  - plan
  - apply

terraform:validate:
  stage: validate
  image: hashicorp/terraform:1.7
  script:
    - terraform init -backend=false
    - terraform validate
    - terraform fmt -check -recursive
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

terraform:plan:
  stage: plan
  image: hashicorp/terraform:1.7
  script:
    - terraform init
    - terraform plan -out=tfplan -var-file="environments/${ENV}/terraform.tfvars"
    - terraform show -json tfplan > tfplan.json
  artifacts:
    paths:
      - tfplan
      - tfplan.json
    expire_in: 1 week
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

terraform:apply:
  stage: apply
  image: hashicorp/terraform:1.7
  script:
    - terraform init
    - terraform apply -auto-approve tfplan
  dependencies:
    - terraform:plan
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual
  environment:
    name: production

when: manual on apply is mandatory for production. Plan runs automatically, apply requires a button click from a person with the right permissions.

How to Set Up Auto-Comment of Plan Results in Pull Request?

The most valuable thing in a terraform pipeline is seeing the diff directly in the PR, without going to CI. For this, we use Atlantis or a custom script with GitHub/GitLab API. Atlantis provides 2x faster feedback thanks to real-time comments compared to built-in solutions.

In GitHub Actions using dflook/terraform-github-actions:

---
- name: Terraform Plan
  uses: dflook/terraform-plan@v1
  with:
    path: infrastructure/
    var_file: |
      environments/production/terraform.tfvars
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

The action automatically adds a comment to the PR with the full terraform plan output: what will be added, changed, deleted. On subsequent commits to the branch, the comment is updated, not recreated.

Atlantis for Team Work — Automated Terraform Setup

If the team is large and needs a full workflow with /atlantis plan and /atlantis apply commands directly from PR comments — Atlantis handles it out of the box. It runs as a separate service (Helm chart in a cluster or standalone VM), subscribes to GitHub/GitLab webhooks.

---
# atlantis.yaml version: 3
projects:
  - name: production
    dir: infrastructure/environments/production
    workspace: production
    autoplan:
      when_modified: ["*.tf", "../modules/**/*.tf"]
      enabled: true
    apply_requirements: [approved, mergeable]
---

apply_requirements: [approved, mergeable] — apply is impossible without PR approval and "mergeable" status (all required checks passed).

Characteristic Atlantis GitLab CI native
Setup Helm chart / standalone built into GitLab
PR comments /atlantis plan via API (dflook/action)
Access control apply_requirements when: manual + RBAC
Multiple repos support out of the box requires per-repo setup
OIDC via IAM role via GitLab CI variables

Security: Credentials in CI

Static AWS credentials in CI Variables are acceptable to start, but the best option is OIDC integration. The CI system obtains a temporary token via OIDC and exchanges it for an IAM role through aws sts assume-role-with-web-identity. No long-lived secrets.

---
- name: Configure AWS credentials via OIDC
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789:role/github-actions-terraform
    aws-region: eu-west-1
---

The IAM role is configured with a trust policy limited to a specific repository and branch. The token lives for 1 hour and cannot leak from the pipeline.

What's Included in the Work (Deliverables)

Stage Result
Audit of current IaC Report with recommendations, state drift assessment
Remote state setup S3/DynamoDB or equivalent with locking, backups
Pipeline (validate+plan+apply) Working CI/CD in your system
OIDC integration IAM role, trust policy, tokens
Auto-comments PR notifications with diff
Documentation and training README, runbook, 2-hour session
Warranty Free support for 1 month after implementation

Timeline and How to Start

Basic plan/apply integration in GitLab CI with remote state — from 1 day. Setup with Atlantis, OIDC, auto-comments, and workspace strategy for multiple environments — from 2 to 3 days. Cost is calculated individually after an audit of your current IaC infrastructure. Get a consultation — our engineers will assess your project and propose the optimal solution.