In multi-VPC AWS environments, each VPC often gets its own Internet Gateway (IGW) or NAT Gateway (NATGW) for outbound internet access. This could lead to higher operational overhead, and increased costs from multiple NAT Gateways. Moreover, security becomes fragmented with multiple entry/exit points to monitor.
Centralized internet egress solves these problems by funneling all outbound internet traffic through a single, well-controlled exit point. This architecture isn't just about cost savings—it's about gaining visibility, control, and security over your organization's internet-bound traffic.
In this post, will examine how this can be achieved with two key enabling AWS services: AWS Transit Gateway and the newly released AWS Regional Gateway as well as some key design trade-offs.
Architecture Overview
Centralized egress patterns use AWS Transit Gateway as the routing hub connecting multiple spoke VPCs to a dedicated Egress VPC containing a single Regional NAT Gateway.
Single internet exit point with AWS Regional NAT Gateway and AWS Transit Gateway
Key Components
This architecture comprises three critical layers:
Egress VPC - The Internet Gateway
The Egress VPC is a single centralized exit point for all internet-bound traffic in the Region. The main components within this VPC are the Internet Gateway (IGW) and the Regional NAT Gateway (NATGW). The Regional NATGW provides a single construct which spans multiple availability zones eliminating the need to deploy and manage multiple Zonal NATGWs. Due to the deployment model of the Regional NATGW, manually assigning Elastic IPs is not necessary.
From a design perspective, only private subnets are required from the Transit Gateways attachment subnets. This layer is only for infrastructure routing and hosts no workloads.
Transit Gateway (TGW) - The Regional Router
The TGW connects all the spoke VPCs to the Egress VPC via attachments and enforces routing policies. All outbound internet traffic from spoke VPCs will be routed to the Egress VPC and vice-versa for the inbound return traffic.
The default route table and default propagation will be disabled in favor of explicit control via two custom route tables:
Application Route Table: To be used by Spoke VPCs with blackhole routes to prevent cross-VPC communication
Egress Route Table: For the Egress VPC to route traffic back to the specific spoke VPCs
RFC 1918 prefixes will also be blackholed to prevent lateral movements between spokes.
Client VPCs - Workload VPCs
These VPCs host private application workloads with controlled internet access. The VPCs are completely isolated from each other. Since no direct internet access is allowed on this VPCs, they will only host private subnets for the workloads and also for the TGW attachments.
No IGWs, public subnets or Zonal NATGWs are permitted in these VPCs
Routing Path
Let’s examine what happens when an instance in a spoke VPC wants to download patches from the internet after obtaining the public IP address from DNS resolution.
Source Subnet (VPC-A): The instance sends the packet with the DNS resolved Public IP as the destination. The subnet's Route Table intercepts the request for which matches the 0.0.0.0/0 route entry. Instead of pointing to a local gateway, the route directs this traffic to a Transit Gateway (TGW) attachment.
Transit Gateway: The packet enters the TGW. The TGW consults its own TGW Route Table associated with VPC-A. A static route for the internet (0.0.0.0/0) directs the packet to the attachment for the Centralized Egress VPC.
Egress VPC Entrance: The packet arrives in the Egress VPC. It lands in a "Transit Subnet" where the Subnet Route Table is configured to send all outbound traffic to a NAT Gateway. (0.0.0.0/0 → nat-1234)
Network Address Translation: The Regional NAT Gateway receives the packet, replaces theinstance's private IP with its own Public IP, and prepares it for the public internet.
Internet Gateway (IGW): The NAT Gateway’ route table directs 0.0.0.0/0 to the IGW, which finally routes the packet to the public destination.
The Return Journey: The response follows the same path in reverse. The Regional NATGWuses its internal translation table to ensure the response is sent back through the TGW to the specific instance in VPC-A that started the request.
Key Configurations
In this scenario, we will use two spoke VPCs, VPC_A and VPC_B with EC2 instances requiring internet egress routing to the Egress VPC.
Below are the VPC CIDR ranges for the VPCs.
VPC Name Tag
IPv4 CIDR
egress-vpc
10.255.0.0/16
vpc-a
10.0.0.0/16
vpc-b
10.1.0.0/16
The table below shows the mappings of the various subnets and Availability Zones (AZs) in each of the VPCs.
Subnet Name Tag
VPC
AZ
IPv4 CIDR
egress-pri-tgw-use1a
egress-vpc
us-east-1a
10.255.3.0/28
egress-pri-tgw-use1b
egress-vpc
us-east-1b
10.255.3.16/28
vpc-a-pri-use1a
vpc-a
us-east-1a
10.0.1.0/24
vpc-a-pri-use1b
vpc-a
us-east-1b
10.0.2.0/24
vpc-a-pri-tgw-use1a
vpc-a
us-east-1a
10.0.3.0/28
vpc-a-pri-tgw-use1b
vpc-a
us-east-1b
10.0.3.16/28
vpc-a-pri-use1a
vpc-b
us-east-1a
10.1.1.0/24
vpc-a-pri-use1b
vpc-b
us-east-1b
10.1.2.0/24
vpc-a-pri-tgw-use1a
vpc-b
us-east-1a
10.1.3.0/28
vpc-a-pri-tgw-use1b
vpc-b
us-east-1b
10.1.3.16/28
The table below shows the mappings of the TGW to the Spoke and Egress VPCs;
Attachment Type
Attachment Name Tag
Subnets Name Tag
VPC
egress-attachment
egress_tgw_az1 egress_tgw_az2
VPC
vpc-a-attachment
vpc_a_tgw_az1
vpc_a_tgw_az2
VPC
vpc-b-attachment
vpc_b_tgw_az1 vpc_b_tgw_az2
Spoke VPC Configurations
The route tables for subnets where resources require internet egress need to route internet traffic to the TGW ENI. Below is a snippet for VPC_A. The depends_on is necessary because the TGW attachment needs to exist first before it can be referenced.
To guarantee explicit routing control, the DefaultRouteTableAssociation and DefaultRouteTablePropagation will be disabled in favor of the following route tables
A single Regional NATGW resource set up in Automatic mode, providing automatic failover without the need to manage multiple NAT Gateways for redundancy.
Transit Gateway: ~$0.05/hour per attachment + $0.02/GB data processing
NAT Gateway: ~$0.045/hour per AZ + $0.045/GB processed
Data transfer out to internet For testing, keep resources small and delete the stack promptly. In production, use multiple NAT GWs (one per AZ) for HA and scale.
Step-by-Step Implementation
1. Clone the Repository and Review the Template
git clone https://github.com/FonNkwenti/tf-centralized-nat-egress.git
cd tf-centralized-nat-egress
2. Initialize Terraform and deploy
# Initialize Terraformterraform init
# Review the execution planterraform plan
# Deploy the infrastructureterraform apply -auto-approve
3. Note the Outputs
After successful deployment, Terraform will display EC2 Instance Connect commands:
# Use the command from terraform outputaws ec2-instance-connect ssh --instance-id <vpc-a-instance-id> --connection-type eice --region us-east-1
2. Test internet access:
curl -I https://www.amazon.com
Expected: HTTP 200 response
3. Test AWS API access:
curl -I https://ec2.amazonaws.com
Expected: HTTP 200 response
Test VPC Isolation
1. From VPC_A instance, try to ping VPC_B instance:Expected: 100% packet loss (timeout due to blackhole routes)
# Get VPC_B instance private IP from terraform outputping -c 3 <vpc-b-private-ip>
Cleanup
To destroy all resources:
terraform destroy
Type yes when prompted to confirm.
Cost Considerations
Understanding the cost-benefit ratio of centralized egress requires looking at three primary dimensions:
Fixed Hourly Charges: AWS charges for the "uptime" of resources like NAT Gateways and Transit Gateway attachments.
Data Processing Fees: Both NAT Gateways and Transit Gateways charge a per-GB fee for traffic passing through them.
Redundancy Multiplier: In a distributed architecture, achieving High Availability (HA) across multiple AZs usually requires duplicating Zonal NAT Gateways in each zone, doubling your fixed costs per VPC.
Let's compare the costs for an organization running 5 spoke VPCs, assuming a standard 3-AZ deployment for high availability.
Distributed Architecture
In this model, each VPC has its own Zonal NAT Gateway in each of the 3 AZs to ensure connectivity if any zone fails.
Data Processing: $0.02 (TGW) + $0.045 (NAT) = $0.065 per GB
The table above shows there is a possibility for massive fixed cost savings by centralizing your internet egress traffic. But it isn’t a golden rule.
Remember, good design and architecture is about trade-offs which are always evolving so you must review if centralizing your internet egress makes sense for you.
Conclusion
You now have a production-ready pattern for centralized internet egress: all internet traffic funnels through one controlled point while preserving isolation. Benefits include simplified security (one firewall/inspection point), reduced NAT costs at scale, easier compliance/logging, and cleaner architecture.
Key Takeaways:
Disable default TGW route tables for explicit control.
Use separate TGW route tables for spokes vs. egress.
Always blackhole private CIDR ranges in the spoke route table.
Attach to private subnets only.
Review the amount of data processed
You may also extend this by adding more spokes, replacing the Regional NATGW with a third-party appliance, or integrating VPC endpoints.
At Serverless Guru, we're a collective of proactive solution finders. We prioritize genuineness, forward-thinking vision, and above all, we commit to diligently serving our members each and every day.
In multi-VPC AWS environments, each VPC often gets its own Internet Gateway (IGW) or NAT Gateway (NATGW) for outbound internet access. This could lead to higher operational overhead, and increased costs from multiple NAT Gateways. Moreover, security becomes fragmented with multiple entry/exit points to monitor.
Centralized internet egress solves these problems by funneling all outbound internet traffic through a single, well-controlled exit point. This architecture isn't just about cost savings—it's about gaining visibility, control, and security over your organization's internet-bound traffic.
In this post, will examine how this can be achieved with two key enabling AWS services: AWS Transit Gateway and the newly released AWS Regional Gateway as well as some key design trade-offs.
Architecture Overview
Centralized egress patterns use AWS Transit Gateway as the routing hub connecting multiple spoke VPCs to a dedicated Egress VPC containing a single Regional NAT Gateway.
Single internet exit point with AWS Regional NAT Gateway and AWS Transit Gateway
Key Components
This architecture comprises three critical layers:
Egress VPC - The Internet Gateway
The Egress VPC is a single centralized exit point for all internet-bound traffic in the Region. The main components within this VPC are the Internet Gateway (IGW) and the Regional NAT Gateway (NATGW). The Regional NATGW provides a single construct which spans multiple availability zones eliminating the need to deploy and manage multiple Zonal NATGWs. Due to the deployment model of the Regional NATGW, manually assigning Elastic IPs is not necessary.
From a design perspective, only private subnets are required from the Transit Gateways attachment subnets. This layer is only for infrastructure routing and hosts no workloads.
Transit Gateway (TGW) - The Regional Router
The TGW connects all the spoke VPCs to the Egress VPC via attachments and enforces routing policies. All outbound internet traffic from spoke VPCs will be routed to the Egress VPC and vice-versa for the inbound return traffic.
The default route table and default propagation will be disabled in favor of explicit control via two custom route tables:
Application Route Table: To be used by Spoke VPCs with blackhole routes to prevent cross-VPC communication
Egress Route Table: For the Egress VPC to route traffic back to the specific spoke VPCs
RFC 1918 prefixes will also be blackholed to prevent lateral movements between spokes.
Client VPCs - Workload VPCs
These VPCs host private application workloads with controlled internet access. The VPCs are completely isolated from each other. Since no direct internet access is allowed on this VPCs, they will only host private subnets for the workloads and also for the TGW attachments.
No IGWs, public subnets or Zonal NATGWs are permitted in these VPCs
Routing Path
Let’s examine what happens when an instance in a spoke VPC wants to download patches from the internet after obtaining the public IP address from DNS resolution.
Source Subnet (VPC-A): The instance sends the packet with the DNS resolved Public IP as the destination. The subnet's Route Table intercepts the request for which matches the 0.0.0.0/0 route entry. Instead of pointing to a local gateway, the route directs this traffic to a Transit Gateway (TGW) attachment.
Transit Gateway: The packet enters the TGW. The TGW consults its own TGW Route Table associated with VPC-A. A static route for the internet (0.0.0.0/0) directs the packet to the attachment for the Centralized Egress VPC.
Egress VPC Entrance: The packet arrives in the Egress VPC. It lands in a "Transit Subnet" where the Subnet Route Table is configured to send all outbound traffic to a NAT Gateway. (0.0.0.0/0 → nat-1234)
Network Address Translation: The Regional NAT Gateway receives the packet, replaces theinstance's private IP with its own Public IP, and prepares it for the public internet.
Internet Gateway (IGW): The NAT Gateway’ route table directs 0.0.0.0/0 to the IGW, which finally routes the packet to the public destination.
The Return Journey: The response follows the same path in reverse. The Regional NATGWuses its internal translation table to ensure the response is sent back through the TGW to the specific instance in VPC-A that started the request.
Key Configurations
In this scenario, we will use two spoke VPCs, VPC_A and VPC_B with EC2 instances requiring internet egress routing to the Egress VPC.
Below are the VPC CIDR ranges for the VPCs.
VPC Name Tag
IPv4 CIDR
egress-vpc
10.255.0.0/16
vpc-a
10.0.0.0/16
vpc-b
10.1.0.0/16
The table below shows the mappings of the various subnets and Availability Zones (AZs) in each of the VPCs.
Subnet Name Tag
VPC
AZ
IPv4 CIDR
egress-pri-tgw-use1a
egress-vpc
us-east-1a
10.255.3.0/28
egress-pri-tgw-use1b
egress-vpc
us-east-1b
10.255.3.16/28
vpc-a-pri-use1a
vpc-a
us-east-1a
10.0.1.0/24
vpc-a-pri-use1b
vpc-a
us-east-1b
10.0.2.0/24
vpc-a-pri-tgw-use1a
vpc-a
us-east-1a
10.0.3.0/28
vpc-a-pri-tgw-use1b
vpc-a
us-east-1b
10.0.3.16/28
vpc-a-pri-use1a
vpc-b
us-east-1a
10.1.1.0/24
vpc-a-pri-use1b
vpc-b
us-east-1b
10.1.2.0/24
vpc-a-pri-tgw-use1a
vpc-b
us-east-1a
10.1.3.0/28
vpc-a-pri-tgw-use1b
vpc-b
us-east-1b
10.1.3.16/28
The table below shows the mappings of the TGW to the Spoke and Egress VPCs;
Attachment Type
Attachment Name Tag
Subnets Name Tag
VPC
egress-attachment
egress_tgw_az1 egress_tgw_az2
VPC
vpc-a-attachment
vpc_a_tgw_az1
vpc_a_tgw_az2
VPC
vpc-b-attachment
vpc_b_tgw_az1 vpc_b_tgw_az2
Spoke VPC Configurations
The route tables for subnets where resources require internet egress need to route internet traffic to the TGW ENI. Below is a snippet for VPC_A. The depends_on is necessary because the TGW attachment needs to exist first before it can be referenced.
To guarantee explicit routing control, the DefaultRouteTableAssociation and DefaultRouteTablePropagation will be disabled in favor of the following route tables
A single Regional NATGW resource set up in Automatic mode, providing automatic failover without the need to manage multiple NAT Gateways for redundancy.
Transit Gateway: ~$0.05/hour per attachment + $0.02/GB data processing
NAT Gateway: ~$0.045/hour per AZ + $0.045/GB processed
Data transfer out to internet For testing, keep resources small and delete the stack promptly. In production, use multiple NAT GWs (one per AZ) for HA and scale.
Step-by-Step Implementation
1. Clone the Repository and Review the Template
git clone https://github.com/FonNkwenti/tf-centralized-nat-egress.git
cd tf-centralized-nat-egress
2. Initialize Terraform and deploy
# Initialize Terraformterraform init
# Review the execution planterraform plan
# Deploy the infrastructureterraform apply -auto-approve
3. Note the Outputs
After successful deployment, Terraform will display EC2 Instance Connect commands:
# Use the command from terraform outputaws ec2-instance-connect ssh --instance-id <vpc-a-instance-id> --connection-type eice --region us-east-1
2. Test internet access:
curl -I https://www.amazon.com
Expected: HTTP 200 response
3. Test AWS API access:
curl -I https://ec2.amazonaws.com
Expected: HTTP 200 response
Test VPC Isolation
1. From VPC_A instance, try to ping VPC_B instance:Expected: 100% packet loss (timeout due to blackhole routes)
# Get VPC_B instance private IP from terraform outputping -c 3 <vpc-b-private-ip>
Cleanup
To destroy all resources:
terraform destroy
Type yes when prompted to confirm.
Cost Considerations
Understanding the cost-benefit ratio of centralized egress requires looking at three primary dimensions:
Fixed Hourly Charges: AWS charges for the "uptime" of resources like NAT Gateways and Transit Gateway attachments.
Data Processing Fees: Both NAT Gateways and Transit Gateways charge a per-GB fee for traffic passing through them.
Redundancy Multiplier: In a distributed architecture, achieving High Availability (HA) across multiple AZs usually requires duplicating Zonal NAT Gateways in each zone, doubling your fixed costs per VPC.
Let's compare the costs for an organization running 5 spoke VPCs, assuming a standard 3-AZ deployment for high availability.
Distributed Architecture
In this model, each VPC has its own Zonal NAT Gateway in each of the 3 AZs to ensure connectivity if any zone fails.
Data Processing: $0.02 (TGW) + $0.045 (NAT) = $0.065 per GB
The table above shows there is a possibility for massive fixed cost savings by centralizing your internet egress traffic. But it isn’t a golden rule.
Remember, good design and architecture is about trade-offs which are always evolving so you must review if centralizing your internet egress makes sense for you.
Conclusion
You now have a production-ready pattern for centralized internet egress: all internet traffic funnels through one controlled point while preserving isolation. Benefits include simplified security (one firewall/inspection point), reduced NAT costs at scale, easier compliance/logging, and cleaner architecture.
Key Takeaways:
Disable default TGW route tables for explicit control.
Use separate TGW route tables for spokes vs. egress.
Always blackhole private CIDR ranges in the spoke route table.
Attach to private subnets only.
Review the amount of data processed
You may also extend this by adding more spokes, replacing the Regional NATGW with a third-party appliance, or integrating VPC endpoints.