Reputation: 11
I have set up an AWS infrastructure using Terraform, where I have an ECS cluster running Fargate tasks in a VPC (main-vpc). The Fargate tasks need to pull images from DockerHub. For egress, I've set up another VPC (egress-vpc) with public subnets, NAT gateways, and an internet gateway to facilitate outbound traffic. These two VPCs are connected using AWS Transit Gateway.
However, when I launch my Fargate tasks, they remain in the PENDING state and fail to start. The tasks work correctly when I create a test NAT gateway directly in the main-vpc, bypassing the Transit Gateway egress setup. This leads me to believe there's an issue with how I've configured the Transit Gateway or related routes.
Here is the relevant Terraform code for my setup:
tgw.tf
resource "aws_ec2_transit_gateway" "main_tgw" {
default_route_table_association = "enable"
default_route_table_propagation = "enable"
auto_accept_shared_attachments = "enable"
multicast_support = "enable"
vpn_ecmp_support = "disable"
dns_support = "enable"
tags = {
Name = "main-tgw"
}
}
resource "aws_ram_resource_share" "main_tgw_share" {
name = "main-tgw-share"
allow_external_principals = false
}
resource "aws_ram_resource_association" "main_tgw_share_association" {
resource_arn = aws_ec2_transit_gateway.main_tgw.arn
resource_share_arn = aws_ram_resource_share.main_tgw_share.id
}
resource "aws_ram_principal_association" "main_tgw_org_share_association" {
principal = data.aws_organizations_organization.default.arn
resource_share_arn = aws_ram_resource_share.main_tgw_share.arn
}
main-vpc.tf
resource "aws_vpc" "main_vpc" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
tags = {
Name = "main-vpc"
}
}
resource "aws_subnet" "private_subnet_1a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.32.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "private-subnet-1"
}
}
resource "aws_subnet" "private_subnet_1b" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.48.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "private-subnet-2"
}
}
resource "aws_subnet" "public_subnet_1a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.0.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "public-subnet-1"
}
}
resource "aws_subnet" "public_subnet_1b" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.16.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "public-subnet-2"
}
}
resource "aws_internet_gateway" "main_vpc_igw" {
vpc_id = aws_vpc.main_vpc.id
tags = {
Name = "main-vpc-igw"
}
}
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main_vpc_igw.id
}
tags = {
Name = "public-rt"
}
}
resource "aws_route_table_association" "public_rta_1a" {
subnet_id = aws_subnet.public_subnet_1a.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_route_table_association" "public_rta_1b" {
subnet_id = aws_subnet.public_subnet_1b.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_route_table" "private_subnets_rt" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
transit_gateway_id = aws_ec2_transit_gateway.main_tgw.id
}
tags = {
Name = "private-subnet-rt"
}
}
resource "aws_route_table_association" "private_subnet_1_rta" {
subnet_id = aws_subnet.private_subnet_1a.id
route_table_id = aws_route_table.private_subnets_rt.id
}
resource "aws_route_table_association" "private_subnet_2_rta" {
subnet_id = aws_subnet.private_subnet_1b.id
route_table_id = aws_route_table.private_subnets_rt.id
}
resource "aws_ec2_transit_gateway_vpc_attachment" "main_vpc_attachment" {
subnet_ids = [aws_subnet.private_subnet_1a.id, aws_subnet.private_subnet_1b.id]
transit_gateway_id = aws_ec2_transit_gateway.main_tgw.id
vpc_id = aws_vpc.main_vpc.id
tags = {
Name = "main-vpc-tgw-attachment"
}
}
egress-vpc.tf
resource "aws_vpc" "egress_vpc" {
cidr_block = "10.1.0.0/16"
instance_tenancy = "default"
tags = {
Name = "egress-vpc"
}
}
resource "aws_subnet" "egress_vpc_private_subnet_1a" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.32.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "egress-vpc-private-subnet-1"
}
}
resource "aws_subnet" "egress_vpc_private_subnet_1b" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.48.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "egress-vpc-private-subnet-2"
}
}
resource "aws_subnet" "egress_public_subnet" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.0.0/20"
availability_zone = "eu-west-1a"
tags = {
Name = "egress-vpc-public-subnet"
}
}
resource "aws_subnet" "egress_public_subnet_2" {
vpc_id = aws_vpc.egress_vpc.id
cidr_block = "10.1.16.0/20"
availability_zone = "eu-west-1b"
tags = {
Name = "egress-vpc-public-subnet-2"
}
}
resource "aws_internet_gateway" "egress_vpc_internet_gateway" {
vpc_id = aws_vpc.egress_vpc.id
tags = {
Name = "egress-vpc-internet-gateway"
}
}
resource "aws_eip" "egress_vpc_eip" {
domain = "vpc"
tags = {
Name = "egress-vpc-eip"
}
}
resource "aws_nat_gateway" "egress_vpc_nat_gateway" {
allocation_id = aws_eip.egress_vpc_eip.id
subnet_id = aws_subnet.egress_public_subnet.id
tags = {
Name = "egress-vpc-natgw"
}
}
resource "aws_route_table" "egress_vpc_public_rt" {
vpc_id = aws_vpc.egress_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.egress_vpc_internet_gateway.id
}
tags = {
Name = "egress-vpc-public-rt"
}
}
resource "aws_route_table_association" "egress_vpc_public_rta" {
subnet_id = aws_subnet.egress_public_subnet.id
route_table_id = aws_route_table.egress_vpc_public_rt.id
}
resource "aws_route_table_association" "egress_vpc_public_rta_2" {
subnet_id = aws_subnet.egress_public_subnet_2.id
route_table_id = aws_route_table.egress_vpc_public_rt.id
}
resource "aws_route_table" "egress_vpc_subnets_rt" {
vpc_id = aws_vpc.egress_vpc.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.egress_vpc_nat_gateway.id
}
tags = {
Name = "egress-vpc-private-subnet-rt"
}
}
resource "aws_main_route_table_association" "egress_vpc_main_route_table" {
vpc_id = aws_vpc.egress_vpc.id
route_table_id = aws_route_table.egress_vpc_subnets_rt.id
}
resource "aws_route_table_association" "egress_vpc_private_subnet_1_rta" {
subnet_id = aws_subnet.egress_vpc_private_subnet_1a.id
route_table_id = aws_route_table.egress_vpc_subnets_rt.id
}
resource "aws_route_table_association" "egress_vpc_private_subnet_2_rta" {
subnet_id = aws_subnet.egress_vpc_private_subnet_1b.id
route_table_id = aws_route_table.egress_vpc_subnets_rt.id
}
resource "aws_ec2_transit_gateway_vpc_attachment" "egress_vpc_attachment" {
subnet_ids = [aws_subnet.egress_vpc_private_subnet_1a.id, aws_subnet.egress_vpc_private_subnet_1b.id]
transit_gateway_id = aws_ec2_transit_gateway.main_tgw.id
vpc_id = aws_vpc.egress_vpc.id
tags = {
Name = "egress-vpc-tgw-attachment"
}
}
Upvotes: 0
Views: 184
Reputation: 11
The egress VPC's public route table must have a route back to the TGW to ensure that the response packets from the internet (after going through NAT Gateway) can find their way back to the originating VPC via the TGW.
Adding a route in the public route table of the Egress VPC pointing back to the TGW (for the CIDR range of the originating VPCs) resolved the issue.
Upvotes: 0