
Terraform AWS Infrastructure Blueprint
Terraform modules for provisioning the AWS resources needed to run a containerized backend service: VPC, ECS, ECR, ALB, IAM, and CloudWatch.
The Problem
Every time a new environment was needed, the same AWS resources were created by hand through the console. Steps were forgotten, configurations drifted between environments, and there was no record of what was built or why.
The Solution
Define all infrastructure in Terraform so any environment can be created or destroyed with a single command, with consistent settings and a clear audit trail in version control.
Implementation Details
Problem
Manually creating AWS resources through the console is slow, inconsistent, and hard to audit. When something breaks, it is difficult to know what the intended configuration was. When a second environment is needed, the process starts from scratch.
Architecture
terraform/
├── modules/
│ ├── vpc/ # VPC, subnets, internet gateway, route tables
│ ├── security/ # Security groups for ALB and ECS tasks
│ ├── ecr/ # ECR repository
│ ├── ecs/ # ECS cluster, task definition, service
│ ├── alb/ # Application Load Balancer, target group, listener
│ ├── iam/ # ECS task execution role and policies
│ └── cloudwatch/ # Log group and metric alarms
├── environments/
│ ├── dev/ # dev.tfvars + backend config
│ └── prod/ # prod.tfvars + backend config
├── main.tf
├── variables.tf
└── outputs.tf
Tech Stack
- IaC: Terraform (HCL)
- Networking: AWS VPC, public and private subnets, NAT gateway, internet gateway
- Compute: Amazon ECS (Fargate), task definitions
- Registry: Amazon ECR
- Load Balancing: Application Load Balancer, target group, HTTPS listener
- Security: IAM roles and policies, security groups
- Observability: CloudWatch log groups, metric alarms
- State: S3 remote backend with DynamoDB state locking
What I Built
- VPC with public subnets (ALB) and private subnets (ECS tasks), internet gateway, and route tables
- Security groups: ALB allows inbound 80/443 from the internet; ECS tasks only allow traffic from the ALB security group
- ECR repository with image scanning enabled on push
- ECS cluster and Fargate service wired to the ALB target group; desired count and CPU/memory set per environment via variables
- IAM task execution role with least-privilege policies: ECR pull, CloudWatch Logs, Secrets Manager read
- ALB with an HTTP listener that forwards to the ECS target group
- CloudWatch log group with a configurable retention period
- S3 bucket and DynamoDB table for remote Terraform state and state locking
- Separate
dev.tfvarsandprod.tfvarsfiles so the same modules serve both environments
Deployment Flow
- Developer configures AWS credentials locally (or in CI via OIDC)
terraform init -backend-config=environments/dev/backend.hclinitializes the remote state backendterraform plan -var-file=environments/dev/dev.tfvarspreviews the changesterraform apply -var-file=environments/dev/dev.tfvarsprovisions or updates the infrastructure- Outputs include ALB DNS name, ECR repository URL, and ECS cluster name — consumed by the CI/CD pipeline
Security Decisions
- IAM roles follow least privilege: the ECS task execution role only has the permissions it actually needs
- ECR image scanning is enabled; builds fail if critical vulnerabilities are detected
- Security groups restrict traffic at the network layer before it reaches the application
- Remote state is stored in a private S3 bucket with versioning and server-side encryption; DynamoDB prevents concurrent state mutations
- No credentials or secrets are stored in
.tfvarsfiles or committed to the repository
What I Learned
- Terraform modules make it practical to maintain two environments from one codebase — the discipline is in keeping variables clean and explicit
- Remote state with locking is essential as soon as more than one person or process runs
terraform apply - IAM is the hardest part to get right; starting from zero permissions and adding only what is needed is much safer than starting from
AdministratorAccessand trying to trim terraform planoutput is a useful artifact to attach to pull requests so reviewers can see exactly what will change in AWS