</>inexpresivo

La NAT Gateway de los $5,000

Cómo tres NAT Gateways sin VPC Endpoints triplicaron el costo de AWS en producción — y cómo lo resolvimos.

5 min readDuración: Detección tardía — 3 semanas de costo elevado

Impacto: Costo mensual $650 → $1,900 USD (+192%). ~$15,000 USD/año proyectados.

NAT GatewayVPCLambdaS3DynamoDBCost Explorer
awscost-optimizationvpcnat-gatewaypostmortem

Línea de tiempo del incidente

  • Día 1Despliegue de 15 nuevas Lambdas en subnets privadas
  • Semana 3Factura AWS: $1,900 USD (+192% vs mes anterior)
  • Día 22Abrimos Cost Explorer — NAT Gateway como top 3 de costos
  • Día 22Diagnóstico: Lambdas llamando a S3 y DynamoDB por internet
  • Día 23Crear VPC Endpoints para S3 y DynamoDB (Gateway Endpoints, sin costo adicional)
  • Día 24Consolidar 3 NAT Gateways → 1 (con HA vía routing)
  • Mes siguienteFactura AWS: $620 USD

Todo empezó con una factura de AWS.

Era el 1 de julio, revisando Cost Explorer como rutina mensual, cuando vi el número: $1,900 USD. El mes anterior había sido $650. Sin ningún lanzamiento de producto nuevo. Sin incremento de usuarios. Sin cambios de infraestructura "grandes".

Solo 15 funciones Lambda nuevas.

El contexto

A principios de junio migramos un conjunto de workers de background a AWS Lambda. El requisito de seguridad era claro: las funciones debían estar dentro de la VPC para acceder a recursos en subnets privadas.

El despliegue fue limpio. Tests pasaron. Staging funcionó bien. Pusheamos a producción.

Lo que no notamos fue una consecuencia silenciosa de esa decisión.

El diagnóstico

Al abrir Cost Explorer con el filtro de servicio, el culpable fue inmediato:

NAT Gateway: $890.47

El mes anterior había sido $28.

Filtramos por recurso y encontramos los tres NAT Gateways de la cuenta — uno por availability zone, como buena práctica de alta disponibilidad. Cada uno mostraba un incremento masivo en "DataProcessed".

La pregunta era: ¿qué tráfico estaba pasando por ahí?

El problema de raíz

AWS tiene dos tipos de acceso a sus servicios desde una VPC:

  1. Por internet (a través de NAT Gateway): El tráfico sale a la internet pública, llega al endpoint público de S3/DynamoDB, y regresa. Se cobra por cada GB transferido.

  2. Por VPC Endpoints: El tráfico se queda dentro de la red de AWS. Los Gateway Endpoints para S3 y DynamoDB son gratuitos.

Cada Lambda procesaba en promedio 2MB de datos de S3 por invocación. Con 15 funciones y ~500 invocaciones/día cada una:

15 funciones × 500 invocaciones × 2 MB = 15,000 MB/día = ~450 GB/mes
450 GB × $0.045/GB (NAT processing) = $20.25/día = ~$607/mes solo en datos
+ costo base de 3 NAT Gateways: $96/mes
= ~$703/mes de incremento
plaintext

Los números cuadraban.

La solución

Paso 1: VPC Endpoints para S3 y DynamoDB

Los Gateway Endpoints son la corrección obvia. No tienen costo adicional y el tráfico nunca sale de la red de AWS:

# Gateway Endpoint para S3
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0abc123 \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids rtb-0def456 rtb-0ghi789
 
# Gateway Endpoint para DynamoDB
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0abc123 \
  --service-name com.amazonaws.us-east-1.dynamodb \
  --route-table-ids rtb-0def456 rtb-0ghi789
bash

Terraform equivalente:

resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.${var.region}.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = [aws_route_table.private.id]
}
 
resource "aws_vpc_endpoint" "dynamodb" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.${var.region}.dynamodb"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = [aws_route_table.private.id]
}
hcl

No se requiere cambio en el código de las Lambdas. El SDK de AWS automáticamente usa el endpoint de la VPC cuando está disponible.

Paso 2: Consolidar NAT Gateways

Con los VPC Endpoints en lugar, el tráfico NAT restante era mínimo (acceso a APIs externas ocasional). Consolidamos de 3 a 1 NAT Gateway:

# Una sola NAT Gateway con IP elástica
resource "aws_nat_gateway" "main" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public_a.id  # AZ primaria
}
hcl

Documentamos el procedimiento de failover manual en caso de falla del AZ. Para el volumen de tráfico actual, el tradeoff valió la pena.

Resultado

ConceptoAntesDespuésAhorro
NAT Gateway (datos)$862/mes$8/mes$854/mes
NAT Gateway (base, 3x)$96/mes$32/mes$64/mes
Total$1,900/mes$620/mes$1,280/mes

Ahorro anual proyectado: $15,360 USD.

Lo que cambiaría

El problema no fue técnico — fue de proceso. Teníamos una arquitectura funcional en staging que no capturó el costo real porque:

  1. Staging no tiene el mismo volumen de datos que producción
  2. No revisamos el impacto de costos en el PR de infraestructura
  3. No teníamos alertas de costo configuradas con umbral relativo (% de cambio)

La tercera es la que más duele: AWS Budgets con alertas del 20% de cambio mes a mes habría disparado una alerta en la primera semana, no la tercera.


Este incidente llevó a crear nuestro Checklist de VPC Endpoints — una lista de todos los servicios de AWS que tienen endpoints disponibles y cuándo usarlos.

Pedro Porras

Pedro Porras

TODO: Añadir bio aquí

Get new posts in your inbox

Subscribe