Building a Production-Ready Advanced AWS VPC with Terraform
Building a Production-Ready AWS VPC with Terraform: Multi-AZ Design, NAT Gateways, VPC Endpoints, and Flow Logs
Building a Production-Ready Advanced AWS VPC with Terraform
Every cloud project starts with networking.
Whether you’re planning to deploy EC2 instances, containerized workloads, databases, or an Amazon EKS cluster, a well-designed Virtual Private Cloud (VPC) becomes the foundation that everything else depends on.
Over the years, I’ve seen many teams rush through VPC creation by manually clicking through the AWS console. It works initially, but as environments grow, maintaining consistency across development, staging, and production becomes difficult.
To avoid that problem, I recently built a reusable Terraform configuration that creates a production-ready AWS VPC foundation while remaining flexible enough for future workloads, including Kubernetes, ECS, databases, and shared services.
In this article, I’ll walk through the design decisions, architecture, and Terraform features that make this VPC both scalable and practical for real-world environments.
Architecture Overview
The Terraform configuration automatically selects three Availability Zones in the target AWS region.
The VPC is deployed with:
- Public subnets across three AZs
- Private subnets across three AZs
- Internet Gateway
- Optional NAT Gateways
- Optional VPC Endpoints
- Optional VPC Flow Logs
- Centralized tagging strategy
The architecture looks like this:

This layout provides separation between internet-facing resources and internal workloads while maintaining high availability across multiple availability zones.
Automatic Subnet Allocation
One of the challenges with network design is subnet planning.
Instead of manually calculating CIDR ranges, Terraform automatically generates subnet CIDRs using the cidrsubnet() function.
The default VPC CIDR is:
10.0.0.0/16
Using:
subnet_newbits = 8
Terraform automatically creates /24 subnets.
For example:
Public Subnet 1 10.20.0.0/24
Public Subnet 2 10.20.1.0/24
Public Subnet 3 10.20.2.0/24
Private Subnet 1 10.20.3.0/24
Private Subnet 2 10.20.4.0/24
Private Subnet 3 10.20.5.0/24
This approach eliminates manual calculations and reduces the risk of overlapping subnet allocations.
Public and Private Subnet Strategy
Public subnets are configured with automatic public IP assignment and are intended for resources that require direct internet connectivity.
Examples include:
- Load Balancers
- Bastion Hosts
- NAT Gateways
Private subnets do not assign public IP addresses and are intended for:
- Application servers
- Containers
- Databases
- Internal services
Keeping workloads in private subnets is one of the simplest ways to reduce exposure to the public internet.
Internet Access Design
Public internet connectivity is provided through an Internet Gateway.
The public route table contains:
0.0.0.0/0 -> Internet Gateway
Private workloads often require outbound internet access for:
- Operating system updates
- Package downloads
- Container image pulls
- External API communication
To support that requirement, NAT Gateway deployment is optional.
Choosing the Right NAT Gateway Strategy
One of the most common cost surprises in AWS networking comes from NAT Gateways.
This Terraform design supports two deployment models.
Single NAT Gateway
enable_nat_gateway = true
single_nat_gateway = true
Benefits:
- Lower monthly cost
- Easier management
Trade-offs:
- Single point of failure
- Cross-AZ traffic charges may occur
Ideal for:
- Development
- Testing
- Smaller production environments
NAT Gateway Per Availability Zone
enable_nat_gateway = true
single_nat_gateway = false
Benefits:
- Higher availability
- Better fault tolerance
- Reduced cross-AZ dependency
Trade-offs:
- Increased monthly cost
Ideal for:
- Production workloads
- Mission-critical applications
- Enterprise environments
For most production deployments, I strongly recommend one NAT Gateway per AZ.
Reducing NAT Costs with VPC Endpoints
Many workloads communicate primarily with AWS services rather than the public internet.
Examples include:
- Amazon S3
- Amazon ECR
- AWS STS
- CloudWatch Logs
Without VPC Endpoints, that traffic often flows through NAT Gateways.
To avoid unnecessary NAT costs, this configuration supports both Gateway and Interface VPC Endpoints.
Gateway Endpoint Example
gateway_vpc_endpoints = [
"s3"
]
Traffic to S3 stays entirely within the AWS network.
Interface Endpoint Example
interface_vpc_endpoints = [
"ecr.api",
"ecr.dkr",
"logs",
"sts"
]
These endpoints are deployed in private subnets and secured using a dedicated security group.
For containerized workloads such as EKS, these endpoints can significantly reduce NAT Gateway traffic and improve security.
Network Visibility with VPC Flow Logs
Troubleshooting networking issues without logs can be frustrating.
This configuration includes optional VPC Flow Logs integration.
Enable flow logs using:
enable_flow_logs = true
Terraform automatically provisions:
- CloudWatch Log Group
- IAM Role
- IAM Policy
- VPC Flow Log
The default retention period is 90 days, which is a practical starting point for most environments.
Consistent Tagging Across Resources
As AWS environments grow, tagging becomes increasingly important.
This configuration applies default tags automatically:
Project = var.name
Environment = var.environment
ManagedBy = "terraform"
Terraform = "true"
Additional tags can also be supplied:
additional_tags = {
Owner = "platform"
CostCenter = "shared"
}
Built-In Safety Checks
One feature I always include in Terraform modules is validation.
This VPC configuration includes safeguards for common mistakes, including:
- Invalid CIDR ranges
- Excessive subnet counts
- NAT Gateway deployment without public subnets
- Missing private subnets for interface endpoints
- Invalid flow log configuration
Catching errors during it terraform plan is significantly better than discovering them after deployment.
Preparing for Future Amazon EKS Deployments
Although this VPC is intentionally generic, it was designed with Kubernetes in mind.
Deployment
Clone Terraform Repo:
git clone https://github.com/GogineniManojkumar/cloudops.git
cd cloudops/Terraform/VPC
Initialize Terraform:
terraform init
Review the plan:
terraform plan
Deploy:
terraform apply
Remove resources when no longer needed:
terraform destroy
Final Thoughts
Networking decisions made early in a project tend to stay around for years.
Investing time in a reusable, well-structured Terraform VPC module pays dividends later by improving consistency, reducing operational effort, and making future platform initiatives significantly easier.
By combining multi-AZ networking, optional NAT strategies, VPC endpoints, flow logs, and built-in validation, this Terraform design provides a solid foundation for workloads ranging from traditional EC2 to large-scale Kubernetes environments.
메타데이터
- post_id
- 829f34d644da
- slug
- building-a-production-ready-advanced-aws-vpc-with-terraform-829f34d644da
- url
- https://medium.com/@manojkumarcloud/building-a-production-ready-advanced-aws-vpc-with-terraform-829f34d644da
- canonical_url
- https://medium.com/@manojkumarcloud/building-a-production-ready-advanced-aws-vpc-with-terraform-829f34d644da
- author_url
- https://medium.com/@manojkumarcloud
- status
- ok
- fetched_at
- 2026-06-24 23:31:39