Logo AppDev24 Login / Sign Up
Sign Up
Have Login?
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Login
New Account?
Recovery
Go to Login
By continuing you indicate that you agree to Terms of Service and Privacy Policy of the site.
Terraform

Automating AWS Infrastructure Provisioning with Terraform and GitHub Actions

Updated on Aug 28, 2024

Automating the provisioning of AWS infrastructure is essential for ensuring consistency and minimizing human errors during deployments. With Terraform and GitHub Actions, you can implement a Continuous Delivery (CD) pipeline that deploys to multiple environments (like staging and production) across different AWS accounts.

This blog post will walk you through the process of setting up such a pipeline. In this setup, Terraform State files are centrally managed within an AWS Administrative Account, utilizing S3 buckets for state storage and DynamoDB tables for state locking. The necessary AWS infrastructure services are then deployed to the respective AWS Environment Accounts.

Assumptions

  • AWS Administrative Account (111111111111)
  • AWS Environment Account for Staging (888888888888)
  • AWS Environment Account for Production (999999999999)

The workflow is triggered by a push to specific Github branches (stg for staging and main for production). Based on the branch, it dynamically configures the environment variables and backend settings required to deploy the AWS services to the corresponding AWS account.

Create AWS IAM Roles

Administrative Account

IAM Role

terraform-admin-role (Terraform Administrative Account Role)

Trust Relationships

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::111111111111:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
                    "token.actions.githubusercontent.com:sub": "repo:sarubhai/tf-aws-multi-account-deployment-gh-actions:*"
                }
            }
        }
    ]
}

In order to setup AWS OIDC for Github to access AWS resources refer this article.

Attached IAM Permissions Policy

terraform-admin-policy (Terraform Administrative Account Policy)

  • Policy to allow access to S3 and DynamoDB in the Administrative Account
  • Policy to allow assuming the role in the Environment Accounts
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AccessTerraformState",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::iac-tf-state-gh-actions-dev",
                "arn:aws:s3:::iac-tf-state-gh-actions-dev/*",
                "arn:aws:s3:::iac-tf-state-gh-actions-pro",
                "arn:aws:s3:::iac-tf-state-gh-actions-pro/*"
            ]
        },
        {
            "Sid": "AccessTerraformStateLock",
            "Effect": "Allow",
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:DeleteItem",
                "dynamodb:UpdateItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:eu-central-1:111111111111:table/iac-tf-state-lock-gh-actions-dev",
                "arn:aws:dynamodb:eu-central-1:111111111111:table/iac-tf-state-lock-gh-actions-pro"
            ]
        },
        {
            "Sid": "AssumeAWSEnvironmentAccountRole",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": [
                "arn:aws:iam::888888888888:role/terraform-env-role",
                "arn:aws:iam::999999999999:role/terraform-env-role"
            ]
        }
    ]
}

Environment Accounts

IAM Role

terraform-env-role (Role assumed by Terraform from Administrative Account Role)

Trust Relationships

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/terraform-admin-role"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Attached IAM Permissions Policy

  • Policy to allow access to relevant AWS Services to be provisioned via Terraform
  • E.g. AWS managed policies (AmazonVPCFullAccess, AmazonEC2FullAccess, AmazonS3FullAccess, AmazonRDSFullAccess)

Terraform Configuration

# Provider Configuration
provider "aws" {
  region = "eu-central-1"

  assume_role {
    role_arn = "arn:aws:iam::${var.aws_env_account}:role/terraform-env-role"
  }
}

# Terraform Backend
terraform {
  backend "s3" {
    region  = "eu-central-1"
    key     = "terraform.tfstate"
    acl     = "private"
    encrypt = true
  }
}


# Variables
variable "environment" {
  description = "This environment tag will be included in the environment of the resources."
  default     = "dev"
}

variable "aws_env_account" {
  description = "The AWS environment account to provision the resources."
  default     = "777777777777"
}

variable "vpc_cidr_block" {
  description = "The address space that is used by the virtual network."
  default     = "10.0.0.0/16"
}

# VPC
resource "aws_vpc" "vpc" {
  cidr_block           = var.vpc_cidr_block
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "${var.environment}-vpc"
  }
}

For complete terraform configuration file refer the Github repository.

Add Github Actions Secret

  • AWS_ACCOUNT_ID_ADM: 111111111111
  • AWS_ACCOUNT_ID_STG: 888888888888
  • AWS_ACCOUNT_ID_PRO: 999999999999
  • TFSTATE_BUCKET_STG: iac-tf-state-gh-actions-stg
  • AWS_DYNAMODB_TABLE_STG: iac-tf-state-lock-gh-actions-stg
  • TFSTATE_BUCKET_PRO: iac-tf-state-gh-actions-pro
  • AWS_DYNAMODB_TABLE_PRO: iac-tf-state-lock-gh-actions-pro

GitHub Actions Workflow

name: Terraform-Deployment-Automation
on:
  push:
    branches:
      - stg
      - main

env:
  AWS_REGION: "eu-central-1"
  DEPLOYMENT_ENV: $\{\{ github.head_ref || github.ref_name }}

  AWS_ACCOUNT_ID_ADM: '$\{\{ secrets.AWS_ACCOUNT_ID_ADM }}'
  
  AWS_ACCOUNT_ID_STG: '$\{\{ secrets.AWS_ACCOUNT_ID_STG }}'
  TFSTATE_BUCKET_STG: '$\{\{ secrets.TFSTATE_BUCKET_STG }}'
  AWS_DYNAMODB_TABLE_STG: '$\{\{ secrets.AWS_DYNAMODB_TABLE_STG }}'

  AWS_ACCOUNT_ID_PRO: '$\{\{ secrets.AWS_ACCOUNT_ID_PRO }}'
  TFSTATE_BUCKET_PRO: '$\{\{ secrets.TFSTATE_BUCKET_PRO }}'
  AWS_DYNAMODB_TABLE_PRO: '$\{\{ secrets.AWS_DYNAMODB_TABLE_PRO }}'

permissions:
  id-token: write
  contents: read

jobs:
  terraform-automation-job:
    runs-on: [ubuntu-latest]
    steps:
      
      - name: Check branch and corresponding deployment environment
        run: |
          echo "Branch & Environment To Deploy Artifacts"
          echo ${DEPLOYMENT_ENV}

      - name: Setup Stage Provider & Backend credentials
        if: env.DEPLOYMENT_ENV == 'stg'
        run: |
          echo "Setup Stage Provider & Backend credentials"
          echo "TF_VAR_environment=stg" >> $GITHUB_ENV
          echo "TF_VAR_aws_env_account=${AWS_ACCOUNT_ID_STG}" >> $GITHUB_ENV
          echo "TFSTATE_BUCKET=${TFSTATE_BUCKET_STG}" >> $GITHUB_ENV
          echo "AWS_DYNAMODB_TABLE=${AWS_DYNAMODB_TABLE_STG}" >> $GITHUB_ENV

      - name: Setup Production Provider & Backend credentials
        if: env.DEPLOYMENT_ENV == 'main'
        run: |
          echo "Setup Production Provider & Backend credentials"
          echo "TF_VAR_environment=pro" >> $GITHUB_ENV
          echo "TF_VAR_aws_env_account=${AWS_ACCOUNT_ID_PRO}" >> $GITHUB_ENV
          echo "TFSTATE_BUCKET=${TFSTATE_BUCKET_PRO}" >> $GITHUB_ENV
          echo "AWS_DYNAMODB_TABLE=${AWS_DYNAMODB_TABLE_PRO}" >> $GITHUB_ENV

      - name: Checkout local repo
        uses: actions/checkout@v3
    
      - name: configure aws credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::$\{\{ env.AWS_ACCOUNT_ID_ADM }}:role/terraform-admin-role
          aws-region: $\{\{ env.AWS_REGION }}
          disable-retry: "true"
      
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9.5

      - name: Terraform Init
        run: terraform init -backend-config="bucket=${TFSTATE_BUCKET}" -backend-config="dynamodb_table=${AWS_DYNAMODB_TABLE}"

      - name: Terraform Plan
        run: terraform plan -no-color
        continue-on-error: false

      - name: Terraform Apply
        run: terraform apply --auto-approve
  • The workflow triggers on a push to the stg or main branches.
  • Depending on the branch, the environment variables are set for the corresponding AWS Environment account, S3 bucket, and DynamoDB table. This ensures that the right environment is targeted during the Terraform deployment.
  • The workflow first assumes the AWS administrative account role to access the Terraform state store by using temporary credentials.
  • The workflow then assumes the role in the corresponding AWS environment account to manage infrastructure.

By automating AWS infrastructure provisioning with Terraform and GitHub Actions, you can ensure consistent, reliable, and efficient deployments to multiple environments. The use of centralized state management, environment-specific configuration, and secure handling of secrets further enhances the robustness of this solution.

Implementing this workflow in your CI/CD pipeline will significantly reduce manual errors, streamline deployments, and make your infrastructure as code (IaC) practice more resilient and scalable.

PrimeChess

PrimeChess.org

PrimeChess.org makes elite chess training accessible and affordable for everyone. For the past 6 years, we have offered free chess camps for kids in Singapore and India, and during that time, we also observed many average-rated coaches charging far too much for their services.

To change that, we assembled a team of top-rated coaches including International Masters (IM) or coaches with multiple IM or GM norms, to provide online classes starting from $50 per month (8 classes each month + 4 tournaments)

This affordability is only possible if we get more students. This is why it will be very helpful if you could please pass-on this message to others.

Exclucively For Indian Residents: 
Basic - ₹1500
Intermediate- ₹2000
Advanced - ₹2500

Top 10 Articles