Day 27 – Production Style AWS Infrastructure with Terraform and GitHub Actions CI/CD

Introduction

For Day 27 of my AWS and Terraform learning journey, I wanted to move beyond basic Terraform deployments and simulate a more production style Infrastructure as Code workflow.

The goal of this project was not just to deploy AWS resources manually from a laptop, but to build a deployment pipeline where infrastructure changes are reviewed, approved, and automatically applied through GitHub Actions.

This project included:

  • Terraform based AWS infrastructure deployment
  • GitHub Actions CI/CD workflow
  • AWS OIDC authentication instead of static access keys
  • Protected production approval workflow
  • Auto Scaling Group infrastructure updates through Git commits
  • Multi AZ production style network architecture

Architecture Overview

This architecture includes:

  • VPC with public and private subnets
  • Internet Gateway
  • NAT Gateway
  • Application Load Balancer
  • Auto Scaling Group
  • EC2 instances running Nginx
  • S3 backend for Terraform remote state
  • GitHub Actions CI/CD pipeline
  • GitHub OIDC authentication with AWS IAM Role

Project Structure

The repository was structured to separate infrastructure deployment logic, bootstrap configuration, CI/CD workflows, and helper scripts.

My repository structure included:

.github/workflows
bootstrap-oidc
scripts
main.tf
variables.tf
outputs.tf
providers.tf
locals.tf
versions.tf
user_data.sh
terraform.auto.tfvars

Why I Used GitHub Actions

In real production environments, infrastructure changes are usually not applied manually from a local machine.

Instead, the workflow typically looks like this:

Developer Push
→ Pull Request
→ Terraform Plan
→ Approval
→ Terraform Apply
→ Infrastructure Update

GitHub Actions allowed me to automate this process and simulate a controlled production deployment pipeline.


Terraform Remote Backend

I configured Terraform remote state using Amazon S3.

This allows Terraform state to remain centralized instead of storing it only on a local laptop.

Backend bucket configuration:

bucket       = "jay-terraformstate-bucket"
region = "us-east-1"
encrypt = true
use_lockfile = true

Benefits:

  • Centralized Terraform state
  • State locking support
  • Team collaboration readiness
  • Better operational consistency



AWS Infrastructure Components

The infrastructure deployed through Terraform included:

Networking

  • Custom VPC
  • Public subnets
  • Private subnets
  • Internet Gateway
  • NAT Gateway
  • Route tables

Compute Layer

  • Launch Template
  • Auto Scaling Group
  • EC2 instances
  • User data bootstrap script

Load Balancing

  • Application Load Balancer
  • Target Group
  • Health checks
  • HTTP Listener

Storage

  • S3 bucket for assets and logs

GitHub Actions CI/CD Workflow

The GitHub Actions workflow was responsible for:

  • Terraform formatting validation
  • Terraform initialization
  • Terraform validation
  • Terraform planning
  • Terraform apply
  • Manual production approval

Workflow file location:

.github/workflows/terraform.yml

The workflow used:

environment: Prod

This enabled protected production deployments with approval gates.


AWS OIDC Authentication

One of the most important parts of this project was implementing AWS OIDC authentication for GitHub Actions.

Instead of storing long lived AWS access keys inside GitHub secrets, GitHub Actions authenticated to AWS using temporary credentials.

The workflow assumed an AWS IAM Role using:

aws-actions/configure-aws-credentials@v4

This is a much better security practice compared to storing static access keys in CI/CD systems.

Benefits:

  • No hardcoded AWS credentials
  • Temporary short lived authentication
  • Reduced credential exposure risk
  • Production style security model



Protected Production Approval Workflow

I also implemented a production deployment approval process.

Before Terraform apply executes, GitHub Actions pauses and waits for manual approval.

This simulates a real production deployment gate where infrastructure changes require review before execution.

GitHub Environment:

Prod

Protection Rule:

  • Required reviewer enabled


This was one of the most useful learning experiences because it demonstrated how infrastructure deployments are controlled in enterprise environments.


Testing Infrastructure Changes Through CI/CD

To test the full Infrastructure as Code lifecycle, I updated the Auto Scaling Group desired capacity.

Original value:

desired_capacity = 2

Updated value:

desired_capacity = 3

After committing and pushing the change, GitHub Actions automatically triggered the Terraform workflow.

Terraform detected infrastructure drift and generated the following plan:

desired_capacity = 2 -> 3


This was an important learning moment because it clearly demonstrated how Terraform compares:

  • Desired infrastructure state
  • Terraform state file
  • Actual AWS infrastructure

Terraform then safely modified the Auto Scaling Group in place.


Terraform Apply Through GitHub Actions

After approving the deployment, GitHub Actions automatically executed Terraform apply.

Terraform updated the Auto Scaling Group successfully without recreating the infrastructure.

Terraform output:

Plan: 0 to add, 1 to change, 0 to destroy

This demonstrated safe infrastructure reconciliation through CI/CD.


Auto Scaling Group Validation

After deployment, I verified the infrastructure directly from AWS.

Checks performed:

  • EC2 instances launched successfully
  • Target group health checks passed
  • ALB traffic routing worked correctly
  • Auto Scaling Group updated desired capacity


Application Validation

I validated the deployed application using the ALB DNS endpoint.

Example:

http://day27-prod-infra-prod-alb-xxxxxxxx.us-east-1.elb.amazonaws.com

The application was successfully accessible through the Application Load Balancer.


Key Learnings

This project helped me understand that Infrastructure as Code is not just about writing Terraform scripts.

The bigger learning was understanding how infrastructure changes move through a controlled deployment lifecycle.

Some of the biggest takeaways from this project were:

  • GitHub Actions can fully automate Terraform deployments
  • AWS OIDC is much more secure than static AWS access keys
  • Protected production approvals are critical for infrastructure safety
  • Terraform continuously reconciles desired state against real infrastructure
  • Infrastructure changes can be version controlled just like application code
  • Production style infrastructure workflows require validation, approvals, and controlled deployment processes

Challenges Faced

Availability Zone Compatibility Issue

Initially, Terraform selected an unsupported Availability Zone combination for NAT Gateway and ALB resources.

I fixed this by filtering the Terraform Availability Zone data source to use only standard Availability Zones.

GitHub Actions Workflow Location

At first, GitHub Actions did not detect my workflow because the .github/workflows folder was inside the project folder instead of the repository root.

Moving the workflow folder to the repository root resolved the issue.

OIDC Permission Error

After enabling GitHub Environment protection, AWS OIDC authentication initially failed.

I updated the IAM trust policy to allow:

repo:<org>/<repo>:environment:Prod

which resolved the authorization issue.


Final Thoughts

This was one of the most practical Terraform projects I have worked on so far because it combined:

  • AWS infrastructure
  • Terraform
  • CI/CD automation
  • GitHub Actions
  • IAM security
  • Approval workflows
  • Infrastructure reconciliation

The project helped me better understand how production infrastructure deployments are automated and controlled in real environments.


Cleanup

To destroy the infrastructure:

terraform destroy

To destroy bootstrap OIDC resources:

cd bootstrap-oidc
terraform destroy


Video Reference


Jay

Comments

Popular posts from this blog

ASM Integrity check failed with PRCT-1225 and PRCT-1011 errors while creating database using DBCA on Exadata 3 node RAC

Life is beautiful

Lock Tables in MariaDB