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
- A developer creates a new feature branch to add an S3 bucket and opens a Pull Request.
- GitHub Actions intercepts the PR, pulls the remote state, and runs
.terraform plan - The reviewer checks the generated plan directly inside the GitHub PR comments.
- If approved, the PR is merged into
.main - GitHub Actions detects the merge event and immediately runs
, officially provisioning the S3 bucket in the cloud.terraform apply
This completely eliminates "drift," secures credentials, and provides an immaculate audit log of exactly who changed what, and when.
TerminalDev
AdminFull-stack developer building cool things on the web. Passionate about Next.js, TypeScript, and creating terminal-inspired user interfaces.