Any traffic from a private subnet to S3 or DynamoDB that routes through a NAT Gateway costs $0.045 per GB in NAT data processing fees — on top of the NAT Gateway hourly charge. VPC Gateway Endpoints bypass the NAT Gateway entirely and carry no data processing fee.
The Maths
A workload processing 100 TB/month through NAT Gateway for S3 access costs ~$4,600/month in processing fees alone. The same traffic through a VPC Gateway Endpoint costs $0.
Create the Endpoints
# Get your VPC and route table IDs first
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxxxxxxx \
--service-name com.amazonaws.us-east-1.s3 \
--route-table-ids rtb-xxxxxxxx rtb-yyyyyyyy
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxxxxxxx \
--service-name com.amazonaws.us-east-1.dynamodb \
--route-table-ids rtb-xxxxxxxx rtb-yyyyyyyyVerify Routing
After creation, check that your private subnet route tables have a route for the S3/DynamoDB prefix list pointing to the VPC endpoint (not the NAT Gateway). The AWS console shows this clearly under VPC → Route Tables.
Terraform
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.region}.s3"
route_table_ids = [aws_route_table.private.id]
}