DevOps

Terraform CI/CD with GitHub Actions: Automate Infrastructure Deployments

By CloudFormation Team · 2025-06-14 · 12 min read

Why Automate Terraform?

Manual terraform apply from a developer laptop is a single point of failure. Who ran it? What was the plan? Were there conflicts with another engineer's changes? Automating Terraform through CI/CD solves all of these problems: every change is peer-reviewed, every plan is recorded, every apply is auditable.

OIDC Authentication (No Long-Lived Secrets)

Configure GitHub Actions to authenticate to AWS without storing access keys:

resource "aws_iam_openid_connect_provider" "github" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

resource "aws_iam_role" "github_actions" {
  name = "github-actions-terraform"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = { Federated = aws_iam_openid_connect_provider.github.arn }
      Action = "sts:AssumeRoleWithWebIdentity"
      Condition = {
        StringLike = {
          "token.actions.githubusercontent.com:sub" = "repo:YOUR_ORG/YOUR_REPO:*"
        }
      }
    }]
  })
}

Plan on Pull Request

# .github/workflows/terraform.yml
name: Terraform

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

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~1.7.0"

      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        id: plan
        run: terraform plan -no-color -out=tfplan

      - name: Comment Plan on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const plan = require('fs').readFileSync('plan.txt', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '## Terraform Plan
```
' + plan + '
```'
            });

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

Multi-Environment Promotion

Use separate workflows triggered by branch or Git tag for environment promotion:

jobs:
  deploy-dev:
    if: github.ref == 'refs/heads/develop'
    environment: dev
    steps:
      - run: terraform workspace select dev && terraform apply -auto-approve

  deploy-staging:
    if: github.ref == 'refs/heads/main'
    environment: staging
    needs: [test]
    steps:
      - run: terraform workspace select staging && terraform apply -auto-approve

  deploy-prod:
    if: startsWith(github.ref, 'refs/tags/v')
    environment: production     # requires manual approval in GitHub
    needs: [deploy-staging]
    steps:
      - run: terraform workspace select prod && terraform apply -auto-approve

Cost Estimation with Infracost

      - name: Infracost
        uses: infracost/actions/setup@v2
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}

      - name: Generate cost estimate
        run: |
          infracost breakdown --path=. --format=json --out-file=infracost.json
          infracost comment github --path=infracost.json             --repo=$GITHUB_REPOSITORY             --github-token=${{ github.token }}             --pull-request=${{ github.event.pull_request.number }}
CloudFormation generates GitHub Actions workflows automatically from your canvas design. Click the Pipeline button and select GitHub Actions to get a complete workflow file with plan-on-PR, apply-on-merge, and optional Infracost integration.

Try CloudFormation Free

Design infrastructure visually and generate production-ready Terraform in seconds — 693 resources across 9 cloud providers.

🚀 Open the Designer →