Skip to main content

Command Palette

Search for a command to run...

Terraform and Github Actions to Automate AWS Infra

Published
3 min read

Setting up a robust CI/CD pipeline for Infrastructure as Code is a critical step in any DevOps journey. In this post, we will walk through the process of building a production-grade pipeline using Terraform and GitHub Actions, covering multi-environment management, security scanning, and automated deployments.

Architecture Overview

open the diagram in a new tab for clarity.

Our infrastructure consists of a highly available 2-tier web application architecture. This includes:

  • A VPC with public and private subnets across two Availability Zones.

  • An Application Load Balancer to distribute traffic.

  • An Auto Scaling Group for our EC2 instances running Nginx.

  • Secure state management using an S3 bucket with versioning and encryption.

We use Terraform workspaces to isolate our environments - dev, test, and prod. Ensuring that changes in one environment do not impact the others.

Preparing the AWS Backend

Before we can run our pipeline, we need a secure place to store our Terraform state. We will use an S3 bucket for this purpose.

Run the following commands to create and configure the bucket:

# Create bucket for Terraform state
aws s3 mb s3://staging-my-terraform-bucket-kutt27 --region us-east-1

# Enable versioning for state history
aws s3api put-bucket-versioning \
  --bucket staging-my-terraform-bucket-kutt27 \
  --versioning-configuration Status=Enabled

# Enable encryption
aws s3api put-bucket-encryption \
  --bucket staging-my-terraform-bucket-kutt27 \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "AES256"
      }
    }]
  }'

Make sure to udpate the bucket name to a unique name.

After creating the bucket, update your backend.tf file to point to it:

terraform {
  backend "s3" {
    bucket       = "staging-my-terraform-bucket-kutt27"
    key          = "terraform/state/main/terraform.tfstate"
    region       = "us-east-1"
    use_lockfile = true
    encrypt      = true
  }
}

Setting up GitHub Secrets

To allow GitHub Actions to interact with AWS, we need to provide it with credentials.

  1. Generate an Access Key in the AWS Console under IAM for your user.

  2. In your GitHub repository, navigate to Settings > Secrets and variables > Actions.

  3. Create two new repository secrets:

    • AWS_ACCESS_KEY_ID: Your access key ID.

    • AWS_SECRET_ACCESS_KEY: Your secret access key.

Configuring Environments and Approvals

GitHub Environments allow us to set protection rules, such as requiring manual approval for production deployments.

In your repository:

  1. Go to Settings > Environments.

  2. Create three environments: dev, test, and prod.

  3. For the prod environment, select "Required reviewers" and add yourself or a teammate. This ensures that no code reaches production without a final human check.

Environment-Specific Configurations

Each environment has different requirements for scale and networking. We manage these through .tfvars files.

Development (dev.tfvars)

The dev environment is optimized for cost and speed.

  • environment = "dev"

  • instance_type = "t2.micro"

  • desired_capacity = 2

  • min_size = 1

  • max_size = 2

  • vpc_cidr = "10.0.0.0/16"

Test (test.tfvars)

The test environment mimics production more closely for accurate validation.

  • environment = "test"

  • instance_type = "t2.micro"

  • desired_capacity = 2

  • min_size = 2

  • max_size = 4

  • vpc_cidr = "10.1.0.0/16"

  • public_subnet_cidrs = ["10.1.1.0/24", "10.1.2.0/24"]

  • private_subnet_cidrs = ["10.1.11.0/24", "10.1.12.0/24"]

Production (prod.tfvars)

The production environment is built for scale and reliability.

  • environment = "production"

  • instance_type = "t2.micro"

  • desired_capacity = 2

  • min_size = 2

  • max_size = 10

  • vpc_cidr = "10.2.0.0/16"

  • public_subnet_cidrs = ["10.2.1.0/24", "10.2.2.0/24"]

  • private_subnet_cidrs = ["10.2.11.0/24", "10.2.12.0/24"]

Feature Branch Workflow

A typical workflow involves creating a feature branch for your changes:

git checkout -b feat/scale-up-dev

Once you push your changes and open a pull request, the CI/CD pipeline will automatically:

  1. Run TFLint to check for code quality issues.

  2. Run Trivy to scan for security vulnerabilities.

  3. Initialize Terraform and validate the configuration.

  4. Generate a terraform plan and post it as a comment on the PR.

This visibility ensures that everyone knows exactly what infrastructure changes are being proposed before they are merged.

For any doubts, visit this repo and make changes. Link.


Video Reference:


Arigato!