If you've ever spent an afternoon clicking through the AWS console to wire up a VPC, subnets, an ALB, TLS certificates, and a CloudFront distribution — only to realize you can't remember exactly what you clicked — you already understand the problem manishpcp/terraform-aws-infrastructure sets out to solve.
This is a fully modular, production-oriented Terraform project that codifies an entire multi-tier AWS environment: private compute, a public load balancer, a CDN-backed static site, a containerized microservice, DNS, observability, and CI/CD — all wired together and deployable with a single command.
The Problem It Solves
Manually building secure, observable AWS infrastructure has a few recurring pain points, and this project tackles each one directly:
- Infrastructure drift. Console changes made by different people over time quietly diverge across environments. Here, every resource is declared in code, reviewed in Git, and applied deterministically.
- Overexposed compute. It's common to see EC2 instances sitting directly on the public internet. In this architecture, compute lives in private subnets with no public IPs — only the ALB and NAT Gateways face the internet.
- Certificate babysitting. ACM certificates for both the ALB and CloudFront are provisioned and DNS-validated automatically, removing manual renewal overhead.
- Serving static and dynamic workloads from one domain. Many teams need a static frontend and a dynamic API under the same domain. This stack handles both — CloudFront + S3 for static content, ALB + EC2/Docker for the API — under a single Route 53 hosted zone.
- Missing observability. Fresh EC2 instances typically ship with no logs or metrics. Here, the CloudWatch Agent is installed and configured at boot on every instance automatically.
- Long-lived CI/CD credentials. Instead of storing AWS keys in GitHub, both pipelines authenticate via OIDC, assuming an IAM role with no static credentials anywhere.
- Unbounded container image growth. An ECR lifecycle policy automatically retains only the last 10 images, keeping storage costs in check.
The Architecture
The stack spans two Availability Zones for resilience and separates concerns cleanly between public and private tiers:
- A VPC (
10.0.0.0/16) with 2 public and 2 private subnets, each AZ getting its own NAT Gateway. - Two EC2 instances (t3.small, Amazon Linux 2023) in private subnets, each running Nginx and a Docker container side by side, with encrypted gp3 volumes and IMDSv2 enforced.
- An internet-facing Application Load Balancer with HTTP→HTTPS redirect, TLS 1.3, and host-header-based routing to separate Nginx and Docker target groups.
- S3 + CloudFront for the static site, with Origin Access Control so the bucket is never publicly reachable directly, plus geo-restriction and gzip compression.
-
ECR hosting a Flask/Gunicorn microservice with
/,/health, and/infoendpoints, built and pushed via GitHub Actions. - Route 53 automatically wiring up seven subdomains across the direct EC2 endpoints, the load-balanced endpoints, and the static site.
- CloudWatch log groups and agent-shipped metrics (CPU, memory, disk) from every instance.
- A least-privilege IAM instance profile scoped to CloudWatch, SSM Parameter Store, and ECR read access.
The Technology Stack
- Terraform (>= 1.5.0) with a modular layout — separate modules for VPC, security groups, IAM, EC2, ALB, CloudWatch, Route 53, and S3/CloudFront — plus S3 + DynamoDB for remote state.
- AWS services: VPC, EC2, Application Load Balancer, ACM, S3, CloudFront, Route 53, ECR, CloudWatch, IAM, SSM.
- Nginx as a reverse proxy on each instance, routing subdomain traffic to either a static response or the local Docker container.
- Docker running the containerized workload on each instance.
- Python (Flask + Gunicorn) powering the microservice deployed through ECR.
-
GitHub Actions for CI/CD, using OIDC federation to assume an IAM role rather than storing AWS credentials as secrets — one workflow handles
terraform plan/apply, the other builds and pushes the Docker image.
Why It's Worth a Look
What stands out about this repo isn't just that it automates AWS provisioning — plenty of projects do that. It's that it demonstrates a genuinely production-shaped pattern: private-by-default compute, automatic TLS, OIDC-based CI/CD instead of static keys, built-in observability, and a real cost breakdown (roughly $125–135/month at low traffic, with NAT Gateways called out as the biggest line item and a suggestion to consolidate them for non-prod environments).
The README also includes an honest security review — flagging an outdated Gunicorn version vulnerable to request smuggling, a Flask cache header issue, S3 public access block settings that need tightening, and a couple of ALB hardening steps. That kind of transparency about what still needs fixing before real production use is refreshingly rare in reference infrastructure projects.
If you're learning Terraform module design, looking for a realistic multi-tier AWS reference architecture, or just want a batteries-included starting point for a hybrid static-site-plus-microservice setup, this repository is a solid one to study — and to fork.
Top comments (0)