cd ..
🏷️ Terraform🏷️ GitHub Actions🏷️ GitOps🏷️ CI/CD🏷️ Automation

Zero to GitOps: Automating Infrastructure with GitHub Actions and Terraform

Zero to GitOps: Automating Infrastructure with GitHub Actions and Terraform

Zero to GitOps: Automating Infrastructure with GitHub Actions and Terraform

In early DevOps iterations, "Infrastructure as Code" often meant a developer running

terraform apply
from their local laptop while hoping nobody else was running a command at the same time.

Today, manual alterations are considered antipatterns. True infrastructure automation requires GitOps—the practice where your Git repository is the absolute single source of truth, and pipelines execute all changes autonomously.

The Objective

We are going to build a GitHub Action workflow that will automatically

plan
our Terraform code when a Pull Request is opened, and
apply
the code immediately upon tracking to the
main
branch.

Step 1: Secure Remote State

Terraform must store a "state file" to understand the difference between your code and the actual cloud reality. Running this in a CI/CD pipeline requires a secured, remote backend.

In AWS, we define an S3 bucket and a DynamoDB block for locking:

terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "global/s3/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-up-and-running-locks"
    encrypt        = true
  }
}

Step 2: Injecting Cloud Credentials

You cannot push AWS Access Keys to a GitHub repository. Instead, configure AWS OIDC (OpenID Connect) to trust your specific GitHub repository.

Once established, GitHub Actions can request ephemeral, short-lived tokens on the fly without storing any permanent credentials.

Step 3: The GitHub Actions Workflow

Create a file at

.github/workflows/terraform.yml
.

name: 'Terraform Infrastructure Pipeline'

on:
  push:
    branches: [ "main" ]
  pull_request:

permissions:
  id-token: write # Required for AWS OIDC
  contents: read

jobs:
  terraform:
    name: 'Terraform'
    runs-on: ubuntu-latest

    steps:
    - name: Checkout Repository
      uses: actions/checkout@v3

    - name: Configure AWS Credentials using OIDC
      uses: aws-actions/configure-aws-credentials@v2
      with:
        role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
        aws-region: us-east-1

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v2

    - name: Terraform Init
      run: terraform init

    - name: Terraform Format
      run: terraform fmt -check

    - name: Terraform Plan
      if: github.event_name == 'pull_request'
      run: terraform plan -no-color

    - name: Terraform Apply
      if: github.ref == 'refs/heads/main' && github.event_name == 'push'
      run: terraform apply -auto-approve -input=false

The Resulting Workflow

  1. A developer creates a new feature branch to add an S3 bucket and opens a Pull Request.
  2. GitHub Actions intercepts the PR, pulls the remote state, and runs
    terraform plan
    .
  3. The reviewer checks the generated plan directly inside the GitHub PR comments.
  4. If approved, the PR is merged into
    main
    .
  5. GitHub Actions detects the merge event and immediately runs
    terraform apply
    , officially provisioning the S3 bucket in the cloud.

This completely eliminates "drift," secures credentials, and provides an immaculate audit log of exactly who changed what, and when.

T

TerminalDev

Admin

Full-stack developer building cool things on the web. Passionate about Next.js, TypeScript, and creating terminal-inspired user interfaces.

0