Building Production-Ready AWS Three-Tier Architecture with Terraform and GitOps



This content originally appeared on DEV Community and was authored by Renato Mendoza

Modern web applications demand scalable, secure, and maintainable infrastructure. This project demonstrates how to deploy a complete three-tier architecture on AWS using Terraform with professional CI/CD workflows.

What You’ll Build

A production-ready architecture featuring:

  • Web Tier: Application Load Balancer with SSL termination and Auto Scaling Groups
  • Application Tier: EC2 instances running PHP web application in private subnets
  • Database Tier: RDS MySQL with Multi-AZ support and encrypted storage

Key Features

🔒 Security First

  • Private subnets for application and database tiers
  • AWS Secrets Manager integration for database credentials
  • OIDC authentication (no long-term AWS keys)
  • Security groups with least-privilege access

🚀 GitOps Workflow

  • Environment-specific branches (env/dev, env/staging, env/prod)
  • Automated Terraform validation and planning on PRs
  • Manual approval gates for production deployments
  • Safe destroy workflows with confirmation requirements

📊 Infrastructure as Code

  • Modular Terraform design for reusability
  • Remote state management with S3 and DynamoDB
  • Environment-specific configurations
  • Comprehensive output values

Project Structure

aws-three-tier-terraform-cicd/
├── .github/workflows/
│   └── terraform.yaml         # CI/CD pipeline
├── docs/
│   └── MANUAL_WORKFLOWS.md    # Manual workflow documentation
├── infra/envs/
│   ├── dev/                   # Development environment config
│   │   └── terraform.tfvars   # Dev-specific variables
│   ├── staging/               # Staging environment config
│   │   └── terraform.tfvars   # Staging-specific variables
│   ├── prod/                  # Production environment config
│   │   └── terraform.tfvars   # Production-specific variables
│   ├── main.tf                # Main infrastructure configuration
│   ├── variables.tf           # Input variables
│   ├── locals.tf              # Local values
│   └── versions.tf            # Terraform and provider versions
├── modules/
│   ├── application/           # Application tier module
│   │   ├── main.tf            # Application module implementation
│   │   ├── variables.tf       # Application module variables
│   │   └── outputs.tf         # Application module outputs
│   └── network/               # Network tier module
│       ├── main.tf            # Network module implementation
│       ├── variables.tf       # Network module variables
│       └── outputs.tf         # Network module outputs
└── scripts/                   # Helper scripts

Quick Start

  1. Fork the repository and configure GitHub secrets:
   DB_PASSWORD          # Database password
   AWS_ROLE_ARN         # OIDC role ARN

For detailed instructions on setting up OIDC authentication and configuring the Terraform backend, see: one-click-aws-terraform-backend-gitops-oidc

  1. Set GitHub variables:
   AWS_REGION           # Target AWS region
   TF_BACKEND_*         # Terraform backend config
  1. Configure environment by copying terraform.tfvars.example:
   region = "us-west-2"
   env_name = "dev"
   certificate_arn = "arn:aws:acm:..."
   domain_name = "yourdomain.com"
  1. Deploy using GitOps:
    • Create PR to environment branches → Terraform format check, validation, and plan
    • Merge to env/dev → Deploy to development
    • Merge to env/staging → Deploy to staging
    • Merge to env/prod → Deploy to production (with manual approval)

CI/CD Pipeline Highlights

The GitHub Actions workflow provides:

  • Automated Planning: Terraform plans run on every PR with results commented
  • Environment Isolation: Separate workspaces for dev/staging/prod
  • Security Gates: Manual approval required for production changes
  • Safe Destruction: Multi-step confirmation for infrastructure teardown

Database Security

Credentials are handled through multiple security layers:

  1. GitHub Secrets store the master password
  2. AWS Secrets Manager receives the password via CI/CD
  3. IAM Roles allow EC2 instances to retrieve credentials
  4. No Hardcoding – passwords never appear in code or state

Production Considerations

  • Configure DNS manually (project doesn’t create Route53 records)
  • Enable VPC Flow Logs for network monitoring
  • Use remote state backend for team collaboration

Why This Approach Works

This architecture pattern provides:

  • Scalability: Auto Scaling Groups handle traffic spikes
  • Security: Multi-layered security with private networking
  • Reliability: Multi-AZ deployment with load balancing
  • Maintainability: Modular Terraform with GitOps workflows
  • Cost Efficiency: Environment-specific scaling configurations

Ready to deploy enterprise-grade infrastructure? Check out the full repository for complete implementation details.


This content originally appeared on DEV Community and was authored by Renato Mendoza