Production-grade AWS VPC with multi-tier subnets, NAT Gateways, VPC Flow Logs, VPC Endpoints, DHCP Options, and IPv6 dual-stack support.
This module provisions a fully-featured AWS VPC with five distinct subnet tiers (public, private, database, intra, and elasticache), enabling defense-in-depth network segmentation. It supports high-availability NAT Gateway deployment (per-AZ or single), IPv6 dual-stack networking, VPC Flow Logs with KMS encryption, gateway endpoints (S3, DynamoDB), interface endpoints for private AWS service access, custom DHCP options, VPN Gateway, and default security group lockdown. Sub-modules provide IPAM integration, VPC peering, and standalone flow log configuration. All resources follow consistent naming and tagging conventions.
Public, Private, Database, Intra (no internet), ElastiCache
VPC, subnets, route tables, NAT GW, IGW, EIGW, VPN GW, endpoints, SG, NACL, DHCP, flow logs
IPAM, VPC Peering, Flow Logs
CIDRs, AZs, NAT, VPN, endpoints, DHCP, flow logs, tags
| Component | Resource(s) | Purpose |
|---|---|---|
| VPC | aws_vpc, aws_vpc_ipv4_cidr_block_association | Primary + secondary CIDR blocks, DNS support/hostnames, IPv6 |
| Internet Gateway | aws_internet_gateway, aws_egress_only_internet_gateway | Public internet access, IPv6 egress-only for private subnets |
| Public Subnets | aws_subnet, aws_route_table, routes | Multi-AZ with auto-assign public IP, IGW route, IPv6 |
| Private Subnets | aws_subnet, aws_route_table, NAT routes | Multi-AZ workload tier with NAT GW outbound access |
| Database Subnets | aws_subnet, aws_db_subnet_group | Isolated DB tier with auto-created DB subnet group |
| Intra Subnets | aws_subnet, aws_route_table (no routes) | Completely isolated subnets with no internet access |
| ElastiCache Subnets | aws_subnet, aws_elasticache_subnet_group | Cache tier with auto-created ElastiCache subnet group |
| NAT Gateways | aws_nat_gateway, aws_eip | Per-AZ (HA) or single NAT for private subnet outbound |
| VPN Gateway | aws_vpn_gateway | Site-to-site VPN with configurable BGP ASN |
| VPC Endpoints | aws_vpc_endpoint (gateway + interface) | S3 and DynamoDB gateway endpoints, interface endpoints for any service |
| Flow Logs | aws_flow_log, aws_cloudwatch_log_group | VPC traffic logging to CloudWatch or S3 with KMS |
| Default SG | aws_default_security_group | Locked down with no rules to prevent accidental use |
| DHCP Options | aws_vpc_dhcp_options | Custom DNS domain, name servers, NTP servers |
Inbound traffic hits the ALB in public subnets, routes to application workloads in private subnets, which query databases in isolated DB subnets. Private subnets access the internet via NAT Gateways for outbound only. Intra subnets have zero internet access. VPC endpoints provide private access to S3 and DynamoDB without traversing the internet.
Default security group managed with zero ingress/egress rules to prevent accidental attachment
VPC Flow Logs with KMS encryption, configurable retention, 60-second aggregation option
Defense-in-depth with public, private, database, intra, and cache subnet tiers with separate route tables
Interface endpoints restricted to HTTPS (443) from VPC CIDR via dedicated security group
Zero-internet subnets for sensitive workloads that must not reach the internet
Egress-only IGW for private IPv6 outbound, auto-assign on public subnets only
| Workload | Configuration |
|---|---|
| EKS / Kubernetes | Private subnets with kubernetes.io/role/internal-elb tags, public for ALB |
| RDS / Aurora | Database subnets with auto-created DB subnet group, no internet access |
| ElastiCache | ElastiCache subnets with auto-created subnet group |
| Serverless | Private subnets with interface endpoints for Lambda VPC access |
| Hybrid Cloud | VPN Gateway with custom DHCP options for DNS integration |
single_nat_gateway = false) in productionenable_flow_logs = trueflow_log_max_aggregation_interval = 60 for security-sensitive environments| Variable | Type | Description |
|---|---|---|
name | string | Name prefix for all resources (1-64 chars) |
cidr_block | string | Primary IPv4 CIDR block |
availability_zones | list(string) | AZs to deploy subnets into (min 1) |
| Variable | Default | Description |
|---|---|---|
enable_ipv6 | false | Enable IPv6 dual-stack |
public_subnet_cidrs | [] | Public subnet CIDRs |
private_subnet_cidrs | [] | Private subnet CIDRs |
database_subnet_cidrs | [] | Database subnet CIDRs |
intra_subnet_cidrs | [] | Intra subnet CIDRs (no internet) |
elasticache_subnet_cidrs | [] | ElastiCache subnet CIDRs |
enable_nat_gateway | true | Enable NAT Gateway(s) |
single_nat_gateway | false | Single NAT for all AZs |
enable_flow_logs | true | Enable VPC Flow Logs |
enable_s3_endpoint | true | S3 gateway endpoint |
manage_default_security_group | true | Lock down default SG |
| Resource | Monthly Cost |
|---|---|
| VPC + Subnets | Free |
| NAT Gateway (per AZ) | ~$32 + $0.045/GB |
| VPN Gateway | ~$36 |
| S3/DynamoDB Gateway Endpoints | Free |
| Interface Endpoint (per AZ) | ~$7.20 |
| Flow Logs (CloudWatch) | $0.50/GB ingested |
| KMS Key | $1 + $0.03/10K requests |
module "vpc" {
source = "github.com/kogunlowo123/terraform-aws-vpc-complete"
name = "prod-vpc"
cidr_block = "10.100.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
public_subnet_cidrs = ["10.100.1.0/24", "10.100.2.0/24", "10.100.3.0/24"]
private_subnet_cidrs = ["10.100.11.0/24", "10.100.12.0/24", "10.100.13.0/24"]
database_subnet_cidrs = ["10.100.21.0/24", "10.100.22.0/24", "10.100.23.0/24"]
enable_nat_gateway = true
single_nat_gateway = false
tags = { Environment = "production" }
}
| AWS VPC Documentation |
| NAT Gateway Best Practices |
| VPC Flow Logs |
| VPC Endpoints |
| Terraform aws_vpc |