Associate a static IP address for Fargate outbound traffic using Terraform

Sometimes, when migrating an application into Fargate, you might find that it has outbound connections to legacy services which require IP whitelisting.

As the IP address with each Fargate task is ephemeral, whitelisting its IP address every time it changes is unsustainable.

One solution is to provision a NAT Gateway with a (static) Elastic IP for outbound traffic, and then use the routing tables to only route traffic to the legacy services with this NAT Gateway (as routing everything through it could quickly become expensive). Note that this solution only works for IPv4 traffic.

Here's how to accomplish this with Terraform, assuming your Fargate task already exists, is inside a VPC, along with an existing IGW and routing tables:

variable "whitelist" {
  description = "CIDR ranges to send through the NAT gateway."
  type        = set(string)
  # The two CIDR ranges below are examples.
  default     = ["1.2.3.4/32", "8.8.8.0/24"]
}

# Need an IP address for the NAT gateway
resource "aws_eip" "mynatip" {
    vpc      = true
}

resource "aws_nat_gateway" "mynatgw" {
    allocation_id = aws_eip.mynatip.id
    subnet_id     = aws_subnet.app.id
    depends_on    = [aws_internet_gateway.igw]
}


# Modify the route table for your apps:
resource "aws_route_table" "apps-rt" {
    vpc_id = aws_vpc.myvpc.id

    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.igw.id
    }

    dynamic "route" {
        for_each = var.whitelist
        content {
            cidr_block = route.value
            nat_gateway_id = aws_nat_gateway.mynatgw.id
        }
    }
}

# Get the outbound IP address for your legacy services to whitelist
output "outbound-ip" {
    value = aws_eip.mynatip.public_ip
}

Running terraform apply should give create everything you need, and then print the outbound IP address your apps will use:

Outputs:

outbound-ip = 5.5.5.5