DevOps·

Deploy Your Terraform IaC with GitHub Actions

Automate Terraform deployments with GitHub Actions. A ready-to-use HCL workflow plus best practices for secure, efficient CI/CD pipelines.

Deploying Terraform infrastructure can be streamlined with GitHub Actions, saving you time and reducing manual errors. Below, I propose a basic workflow that you can customize to fit your specific needs. This workflow assumes you already have a Terraform project set up and want to automate its deployment to your AWS account.

The Workflow File

Create a new file in your repository at .github/workflows/deploy.yml and paste this YAML workflow.

deploy.yml
name: Terraform Deploy

on:
  push:
    branches: [ main ]

env:
  AWS_REGION: us-east-1

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Set up Terraform
        uses: hashicorp/setup-terraform@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::<ACCOUNT_ID>:role/GithubActionsRole
          aws-region: ${{ env.AWS_REGION }}

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan

      - name: Terraform Apply
        run: terraform apply -auto-approve
<ACCOUNT_ID> have to be replaced by your AWS account ID.

OIDC Authentication

This workflow uses OpenID Connect (OIDC) to securely authenticate with AWS, eliminating the need for long-lived credentials. If you’re new to OIDC or need help setting it up, I’ve written a dedicated post explaining how to configure the OIDC connection between GitHub and your AWS account.

The IAM Role Permissions

OIDC controls who can assume the GithubActionsRole, but the role still needs an IAM policy describing what it can do once assumed. For Terraform, that policy boils down to two things:

  • Resource permissions: access to every AWS service your Terraform code manages (S3, VPC, RDS, and so on) so it can create, update, and delete those resources.
  • Backend permissions: if you store state remotely, read/write access to the S3 bucket holding the state file and, when using state locking, to the DynamoDB lock table.
Grant only what your stack actually touches, following the principle of least privilege. Attaching AdministratorAccess is tempting to get moving, but a scoped policy keeps a leaked token from reaching the rest of your account.

Testing

The provided workflow does not include any testing steps. For a robust CI/CD pipeline, consider adding unit and integration tests before the deployment job. This ensures your infrastructure changes are validated before being applied.

Production Best Practices

For production environments, it’s recommended to:

  • Pin all versions: Freeze the versions of Terraform and GitHub Actions to avoid unexpected updates.
  • Use approvals: For critical stacks, require manual approval before deployment.
  • Environment separation: Deploy to different AWS accounts for staging and production.