Designing Reusable Terraform Modules for AWS at Scale
The Problem with Copy-Paste Infrastructure
When I joined Skillmine Technologies, each project team was maintaining their own Terraform configurations. The result was predictable:
- Inconsistent security configurations across projects
- Duplicated effort when AWS released new features or best practices changed
- Drift between environments because staging and production were configured differently
I set out to build a library of reusable Terraform modules that would standardize our AWS infrastructure.
Module Design Principles
1. Opinionated Defaults, Flexible Overrides
Every module ships with secure, production-ready defaults. Teams can override specific values, but the baseline is always secure:
module "vpc" {
source = "git::https://gitlab.internal/infra/terraform-modules.git//vpc"
name = "app-vpc"
cidr_block = "10.0.0.0/16"
availability_zones = ["ap-south-1a", "ap-south-1b", "ap-south-1c"]
# Defaults: private subnets, NAT gateway, flow logs enabled
# Override only what's different
enable_vpn_gateway = true
}
2. Composable, Not Monolithic
Instead of one massive module that creates everything, I built small, focused modules that compose together:
vpc— VPC, subnets, route tables, NAT gatewayseks— EKS cluster, node groups, IRSA rolesrds— RDS instances with multi-AZ, automated backupsiam— IAM roles and policies following least-privilege
3. Built-in Compliance
Security scanning is embedded in the module CI pipeline using tfsec and checkov. Every merge request is automatically scanned, and modules can’t be published with critical findings.
High Availability Pattern
One module I’m particularly proud of is the HA application deployment pattern:
module "ha_app" {
source = "git::https://gitlab.internal/infra/terraform-modules.git//ha-app"
app_name = "payment-service"
environment = "production"
# Multi-AZ deployment
vpc_id = module.vpc.vpc_id
private_subnet_ids = module.vpc.private_subnet_ids
# Auto Scaling
min_size = 2
max_size = 10
desired_size = 3
# ALB
health_check_path = "/health"
certificate_arn = data.aws_acm_certificate.main.arn
}
This single module call provisions:
- Application Load Balancer with HTTPS
- Auto Scaling Group spread across AZs
- Launch template with hardened AMI
- CloudWatch alarms for scaling triggers
- Security groups with least-privilege rules
Results
- Provisioning time reduced from days to hours for new projects
- Zero critical security findings in infrastructure audits
- Consistent environments — staging mirrors production exactly
- Self-service — dev teams can provision infrastructure without platform team involvement
The key insight is that good Terraform modules aren’t just about DRY code — they’re about encoding organizational knowledge and security requirements into reusable building blocks.