Command Palette

Search for a command to run...

Hectal
← All projects

Project 7 of 12 · project brief

AWS Infrastructure with Terraform

VPC, EC2 behind an ALB, RDS, S3, IAM, and CloudWatch, built as reusable Terraform modules with remote state and dev/prod environments.

Intermediate 4–5 days 5 milestones

The scenario

ShopLite moves to AWS. Before containers, the team wants the classic three-tier architecture: the API on an Auto Scaling group of EC2 instances behind an Application Load Balancer, PostgreSQL on RDS, uploads on S3, and monitoring in CloudWatch. Everything must be code, reviewable, and reproducible in two environments.

Before you start

Stack

TerraformS3 remote state (with locking)VPCEC2 + Auto Scaling + launch templateALBRDS PostgreSQLS3IAM rolesCloudWatchSSM Session Manager

Target architecture

Project 7 architecturediagram
Rendering diagram…

Deliverables and requirements

You will hand in

  • Terraform modules: network, app (ASG + ALB), database, storage, monitoring
  • envs/dev and envs/prod using the modules with different sizes
  • Remote state in S3 with locking; CI that runs fmt/validate/plan on PRs
  • CloudWatch dashboard and alarms (5xx rate, target health, RDS CPU/storage)

Functional

  • API reachable via the ALB DNS name; unhealthy instances replaced automatically
  • Instances have no SSH keys or public IPs; access via SSM Session Manager
  • App reads the DB password from Secrets Manager and uploads to S3 via its instance role

Non-functional

  • Everything tagged (owner, env, service)
  • RDS encrypted, private, Multi-AZ in prod, backups on
  • terraform plan on a clean checkout shows no changes (no drift)
  • Least-privilege IAM (no *:*)

Milestones

  1. 1

    State and network

    Done when: Remote state bootstrapped; a VPC with public/private subnets across 2+ AZs.

    • Bootstrap an S3 state bucket (versioned, encrypted) with state locking
    • network module: VPC, subnets, IGW, NAT per AZ, route tables
    • Outputs for subnet IDs

    Prove it works

    terminal
    $ terraform -chdir=envs/dev apply && terraform -chdir=envs/dev output -json private_subnet_ids
    ── expected output ──
    ["subnet-0a1b...","subnet-0c2d..."]
  2. 2

    App tier: launch template, ASG, ALB

    Done when: Auto-healing EC2 instances behind a load balancer.

    • Launch template with user data (install JRE, fetch JAR from S3 or run the Docker image, systemd unit)
    • ASG min 2 across private subnets with ELB health checks
    • ALB + target group + listener; security groups allowing only ALB → app
    Stuck? Hints
    • Use an instance profile with AmazonSSMManagedInstanceCore so you never need SSH.

    Prove it works

    terminal
    $ curl -s http://$(terraform -chdir=envs/dev output -raw alb_dns)/actuator/health
    ── expected output ──
    {"status":"UP"}
  3. 3

    Data and storage

    Done when: RDS and S3 wired to the app securely.

    • database module: RDS PostgreSQL in private subnets, SG from app only, password managed in Secrets Manager
    • storage module: S3 bucket, block public access, SSE, lifecycle
    • IAM policy for the instance role: read that secret, read/write that bucket prefix only

    Prove it works

    terminal
    $ aws rds describe-db-instances --db-instance-identifier shoplite-dev --query 'DBInstances[0].[PubliclyAccessible,StorageEncrypted,MultiAZ]'
    ── expected output ──
    [false, true, false]
  4. 4

    Monitoring and environments

    Done when: Alarms, a dashboard, and a prod environment from the same modules.

    • CloudWatch alarms: ALB 5xx > 1%, unhealthy hosts > 0, RDS free storage < 20%, CPU > 80%, notifying SNS
    • Dashboard for the golden signals
    • envs/prod: bigger instances, Multi-AZ RDS, deletion protection

    Prove it works

    terminal
    $ aws cloudwatch describe-alarms --alarm-name-prefix shoplite-prod --query 'MetricAlarms[].AlarmName'
    ── expected output ──
    ["shoplite-prod-alb-5xx","shoplite-prod-unhealthy-hosts","shoplite-prod-rds-cpu","shoplite-prod-rds-storage"]
  5. 5

    CI for Terraform

    Done when: Plans on PRs, applies from main, with OIDC credentials.

    • GitHub Actions with OIDC to assume a role (no long-lived keys)
    • PR: fmt, validate, tflint, checkov, plan posted as a comment
    • Main: apply dev automatically; prod via a protected environment with approval

    Prove it works

    terminal
    $ # PR comment from the pipeline
    ── expected output ──
    Plan: 2 to add, 1 to change, 0 to destroy.

Would you run this in production?

  • ☐Remote state with locking and versioning
  • ☐No hard-coded credentials; OIDC in CI; least-privilege IAM
  • ☐Private subnets for app and data; no SSH
  • ☐Encryption at rest everywhere; backups and deletion protection in prod
  • ☐Alarms routed to a human; tags for cost allocation

Stretch goals

  • Replace EC2 with ECS Fargate (Terraform course, Stage 3)
  • Add CloudFront + WAF in front of the ALB
  • Add terraform test for the modules (Infrastructure Testing guide)

Show it off

Résumé bullet

Designed and provisioned a production-grade three-tier AWS architecture (VPC, ALB, EC2 Auto Scaling, Multi-AZ RDS, S3, CloudWatch) with modular Terraform, remote state, and OIDC-based CI/CD with plan review and gated prod applies.

Demo script

  • Terminate an instance and watch the ASG replace it
  • Show an SSM session instead of SSH
  • Show a PR with a plan comment and the approval gate for prod

Interview questions about this project

01

How do you structure Terraform for multiple environments?

02

Why use SSM Session Manager instead of SSH?