Una VPC no tiene precio de lista. AWS no cobra por crearla, ni por las subnets, ni por las tablas de ruteo, ni por los security groups. La consecuencia mecánica es directa: todo lo que pagás en red es una caja intermedia prendida —un NAT gateway, una ENI de endpoint, una IP pública reservada— o un paquete que cruzó un límite facturado —una frontera de AZ, el borde de la región, la salida a internet. No hay una tercera fuente. El diseño de red no genera costo por ser complejo: lo genera por dónde pone las cajas y por qué límites hace cruzar los bytes.
Lo que sigue es el marco de decisión. Cada sección tiene la misma estructura: qué estás eligiendo, cuánto cuesta cada opción, y qué se rompe si elegís mal. Todos los precios son de us-east-1 y están verificados contra la documentación de AWS a la fecha del encabezado. Los precios cambian; la aritmética no.
Una convención que hay que declarar una sola vez, porque después ordena todas las cuentas: AWS factura la transferencia en GB, y 1 TB son 1024 GB. Por eso un terabyte por el NAT gateway son USD 46,08 y no 45.
La decisión de red más cara de AWS es un checkbox del asistente de la consola que dice "NAT gateway", y se marca antes de que alguien calcule el volumen de tráfico que va a atravesarlo.
Qué hace pública a una subnet
Una subnet es pública si su tabla de ruteo tiene una entrada 0.0.0.0/0 apuntando a un internet gateway. Eso es todo. No hay un flag public: true. La distinción entre subnet pública y privada es una consecuencia del ruteo, y por eso se rompe tan seguido: alguien agrega una ruta para debuggear algo y una subnet que el diagrama declara privada deja de serlo, sin que ningún recurso cambie de nombre.
El internet gateway es gratis. No cobra por hora ni por gigabyte procesado. Lo que sí se cobra es el egress: la transferencia de datos hacia internet, facturada como data transfer out del servicio que la origina, a USD 0,09 por GB en el primer tramo de 10 TB mensuales. AWS regala los primeros 100 GB por mes, agregados entre todos los servicios y regiones.
La otra línea que aparece sin aviso: cada dirección IPv4 pública cuesta USD 0,005 por hora, que son USD 3,65 por mes. Se cobra igual esté atada a algo o esté ociosa —la página de pricing lista el mismo rate para In-use public IPv4 address y para Idle public IPv4 address, y en la factura aparecen como dos usage types separados. Diez instancias con IP pública que nadie necesita son USD 36,50 mensuales de nada, y una Elastic IP olvidada de un experimento cuesta exactamente lo mismo que una en producción.
La decisión concreta acá es cuánto ponés en la subnet pública. El criterio es de superficie de ataque, no de costo: a la subnet pública va solo lo que tiene que recibir conexiones desde afuera —el load balancer, y poco más. Todo lo que solo necesita salir va a privada. Y en ese momento aparece la pregunta cara.
Antes de dimensionar las subnets, un número que muerde tarde: AWS reserva cinco direcciones por subnet —la de red, el router, el DNS, una futura y el broadcast—, así que un /28 deja once IPs usables. Con EC2 clásico alcanza. Con Fargate o EKS, donde cada task y cada pod toma una ENI y una IP, un /28 se agota con once cargas y el síntoma es un deploy que no escala, no un error de red. Esa es una decisión de capacidad disfrazada de decisión de direccionamiento, y se toma una sola vez porque el CIDR de una subnet no se cambia después.
El NAT gateway y la cuenta que casi nadie hace
El NAT gateway le da salida a internet a lo que vive en subnets privadas. Cobra dos veces:
| Concepto | Precio en us-east-1 | Al mes (730 h) |
|---|---|---|
| Disponibilidad por NAT gateway | USD 0,045 por hora | USD 32,85 |
| Data processing | USD 0,045 por GB | según tráfico |
Un NAT gateway por AZ en tres AZs son USD 98,55 por mes fijos, antes de mover un solo byte. Agregá el procesamiento: cada TB (1024 GB) que lo atraviesa suma USD 46,08.
El detalle que hace la diferencia: el data processing se cobra por cada gigabyte que el NAT gateway procesa, sin importar el origen ni el destino del tráfico. La ingesta desde internet hacia AWS es gratis como data transfer, pero si entra por un NAT gateway, el NAT la cobra igual. Un docker pull de una imagen de 1 GB en cada deploy no es gratis: son USD 0,045 por pull. Un job que baja 200 GB de datos externos por mes son USD 9 de NAT, más nada de egress porque el tráfico es entrante.
Sumando en la dirección de salida: un gigabyte que sale de una subnet privada a internet paga USD 0,045 de NAT processing más USD 0,09 de egress. USD 0,135 por GB. Ese número es el que hay que tener en la cabeza cuando alguien propone que el worker mande logs a un SaaS externo.
El NAT gateway también tiene techos duros, y los tres se alcanzan por razones distintas:
| Límite | Valor | Cómo se comporta |
|---|---|---|
| Throughput | 5 Gbps, escala hasta 100 Gbps | crece solo, con demora |
| Paquetes por segundo | 1 millón, escala hasta 10 millones | crece solo, con demora |
| Conexiones simultáneas | 55.000 por combinación de IP destino, puerto y protocolo | no crece: da error |
| Direcciones IP (zonal) | hasta 8 | se agregan a mano |
El de las 55.000 conexiones es el que causa incidentes raros. No es un límite global del NAT: es por destino único. Una flota de workers que abre miles de conexiones contra una sola IP y puerto de un proveedor externo lo agota mientras el resto del tráfico sigue andando. El síntoma es ErrorPortAllocation en CloudWatch y conexiones que fallan solo contra ese destino. La salida es agregar IPs al NAT gateway, no agregar NAT gateways.
Las alternativas tienen precio de lista
Los VPC endpoints sacan tráfico del NAT gateway. Vienen en dos sabores con economías completamente distintas.
Gateway endpoints. Solo existen para S3 y DynamoDB. La documentación de AWS es literal: "There is no additional charge for using gateway endpoints". Sin cargo por hora, sin cargo por GB. Funcionan agregando una ruta a un prefix list gestionado por AWS en las tablas de ruteo que elijas.
No hay breakeven que calcular. Si tenés cargas en subnets privadas que hablan con S3 o DynamoDB, el gateway endpoint es dinero gratis. La única trampa es que el prefix list es regional: el tráfico a un bucket de otra región sigue saliendo por el NAT.
aws ec2 create-vpc-endpoint \
--vpc-id vpc-0abc123 \
--service-name com.amazonaws.us-east-1.s3 \
--route-table-ids rtb-priv-1a rtb-priv-1b rtb-priv-1c
En Terraform es igual de corto:
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.us-east-1.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = [for rt in aws_route_table.private : rt.id]
}
Ese route_table_ids es el modo de falla silencioso más caro del artículo. Un gateway endpoint creado y no asociado a las tablas de ruteo de las subnets privadas existe, aparece en la consola, pasa cualquier auditoría que se limite a preguntar si hay endpoint de S3 —y no ve un solo byte. La ruta al prefix list nunca se inyecta, el tráfico a S3 sigue saliendo por el NAT gateway y se sigue cobrando a USD 0,045 por GB. Nada falla, nadie recibe una alerta, la aplicación anda perfecto. La verificación es una sola: buscar la ruta al prefix list pl- en cada tabla de ruteo privada, no la existencia del endpoint.
# el prefix list de S3 en la región, y qué tablas de ruteo lo tienen
PL=$(aws ec2 describe-prefix-lists \
--filters Name=prefix-list-name,Values=com.amazonaws.us-east-1.s3 \
--query 'PrefixLists[0].PrefixListId' --output text)
aws ec2 describe-route-tables \
--filters Name=route.destination-prefix-list-id,Values="$PL" \
--query 'RouteTables[].RouteTableId'
Interface endpoints (PrivateLink). Cubren la mayoría del resto del catálogo: ECR, Secrets Manager, SSM, CloudWatch Logs, KMS. Cobran USD 0,01 por hora por cada ENI de endpoint —o sea, por AZ— más USD 0,01 por GB. Ese rate por GB corresponde al primer petabyte del mes agregado por región sobre todos los interface endpoints juntos, no por endpoint: una cuenta con veinte endpoints comparte el mismo tramo, no veinte tramos.
Acá sí hay cuenta que hacer:
| Opción | Costo fijo mensual | Costo por GB |
|---|---|---|
| NAT gateway (ya existente) | USD 0 marginal | USD 0,045 |
| Interface endpoint en 3 AZs | USD 21,90 | USD 0,010 |
| Interface endpoint en 2 AZs | USD 14,60 | USD 0,010 |
| Gateway endpoint (S3, DynamoDB) | USD 0 | USD 0 |
El ahorro por gigabyte desviado del NAT al interface endpoint es de USD 0,035. Contra USD 21,90 de costo fijo en tres AZs, el punto de equilibrio está en 626 GB por mes por servicio. En dos AZs, en 417 GB. Por debajo de eso, el endpoint te sale más caro que el NAT — y AWS te va a cobrar los USD 21,90 aunque el endpoint no vea tráfico.
La cuenta cambia por completo si los endpoints te permiten eliminar el NAT gateway entero. Ahí el costo fijo que desaparece son USD 98,55 mensuales, y el umbral se invierte: conviene casi siempre. Ese es el diseño que vale la pena perseguir en cargas que solo hablan con servicios de AWS.
ECR es tres endpoints, no uno
ECR merece su propio párrafo porque el breakeven de 626 GB se aplica mal casi siempre. Cuando un task arranca, pide el manifest de la imagen a la API de ECR y después baja las capas desde S3, que es donde el registry guarda los blobs. Son dos destinos distintos con dos economías distintas.
La configuración correcta son tres endpoints:
| Endpoint | Tipo | Qué transporta | Costo fijo |
|---|---|---|---|
com.amazonaws.us-east-1.ecr.api | interface | autenticación y manifests | USD 7,30 por AZ |
com.amazonaws.us-east-1.ecr.dkr | interface | protocolo del Docker daemon | USD 7,30 por AZ |
com.amazonaws.us-east-1.s3 | gateway | las capas de la imagen | USD 0 |
El volumen real —los cientos de megabytes de cada capa— viaja por el gateway endpoint de S3, que no cuesta nada. Los dos interface endpoints mueven kilobytes de control. Si medís solo el tráfico de ecr.api para decidir si pasás el umbral de 626 GB, la respuesta va a ser que no, y vas a sacar la conclusión equivocada: esos dos endpoints no se justifican por ahorro por gigabyte sino porque son la condición para que el gateway endpoint de S3 absorba el volumen. Y al revés: los dos interface endpoints de ECR sin el gateway de S3 son USD 43,80 mensuales para que las capas sigan bajando por el NAT.
La transferencia entre AZs es la factura fantasma
Los datos que se mueven entre Availability Zones de la misma región se cobran a USD 0,01 por GB en cada dirección. Un ida y vuelta son USD 0,02 por GB, o USD 20,48 por cada terabyte que va y vuelve. En el Cost and Usage Report aparece como USE1-DataTransfer-Regional-Bytes, y AWS documenta que vas a ver dos líneas por cada transferencia, una por cada punta.
Nadie diseña para pagar esto. Se paga por acumulación: la réplica de la base en otra AZ, el service mesh que balancea sin zonal affinity, el consumer de Kafka que lee de un broker en otra zona. Y el caso más caro de todos es el NAT gateway mal ubicado.
Si tenés un solo NAT gateway y cargas en tres AZs, dos tercios de tu tráfico saliente cruza una frontera de AZ antes de llegar al NAT, y vuelve a cruzarla de vuelta. La propia documentación de AWS lo dice sin vueltas: si tus recursos mueven volumen significativo entre AZs, ponelos en la misma AZ que el NAT gateway, o creá un NAT gateway en cada AZ con recursos.
La decisión es un breakeven limpio. Pasar de un NAT a tres suma USD 65,70 mensuales fijos y elimina USD 0,02 por GB de cross-AZ. El punto de equilibrio está en 3.285 GB por mes, o sea 3,2 TB de tránsito entre zonas. Por debajo de eso, un solo NAT gateway es más barato —a cambio de que si esa AZ se cae, las tres se quedan sin salida a internet. Los USD 65,70 mensuales compran aislamiento de fallas zonal. Esa es la decisión, y ahora tiene precio.
En noviembre de 2025 AWS agregó el regional NAT gateway, que se expande y contrae solo entre AZs según dónde detecte network interfaces, con un único ID de NAT para todas las tablas de ruteo. Se factura a USD 0,045 por hora por cada AZ activa, o sea que no es más barato que hacerlo a mano. Lo que compra es menos superficie de error operativo: no hay que crear subnets públicas para hospedarlo ni editar tablas de ruteo cada vez que la carga aterriza en una AZ nueva. Soporta hasta 32 direcciones IP por AZ contra las 8 del zonal, y las agrega solo cuando las conexiones hacia un mismo destino se acercan a unas 40.000 —o sea que corre el techo de puertos sin que nadie lo administre. En contra: la expansión a una AZ nueva puede tardar hasta 60 minutos, y no soporta private NAT.
Security groups contra NACLs: la decisión es operativa, no económica
Ninguno de los dos cuesta plata en la línea de la factura. Se pagan en incidentes — y el incidente termina en la factura por la puerta de atrás, que es el final de esta sección.
Un security group es stateful: si dejás salir una conexión, la respuesta vuelve sin regla explícita. Una network ACL es stateless: cada dirección se evalúa por separado, y el tráfico de retorno necesita su propia regla en el rango de puertos efímeros. Ese detalle es el origen de una clase entera de outages, porque la regla de salida existe, el tráfico sale, y la respuesta muere en silencio en el borde de la subnet.
| Security group | Network ACL | |
|---|---|---|
| Se aplica a | ENI | subnet |
| Estado | stateful | stateless |
| Reglas | solo allow | allow y deny |
| Evaluación | todas las reglas | por número, primera que matchea |
| Default | 60 reglas inbound y 60 outbound, 5 SG por ENI | 20 reglas por dirección |
| Ajustable hasta | 1000 reglas por SG y 16 SG por ENI, con reglas × SG ≤ 1000 | 40 por dirección, con impacto de performance |
Las cuotas importan más de lo que parece. La restricción real no es ninguno de los dos números por separado: es el producto. Reglas por security group multiplicado por security groups por ENI no puede pasar de 1000, así que subir uno te obliga a bajar el otro. Si estás llenando reglas con CIDRs sueltos, vas a chocar contra ese techo. La salida es referenciar otros security groups como origen en vez de rangos de IP: una regla que dice "el SG de la app puede hablar con el puerto 5432 del SG de la base" no crece cuando escalás.
Las NACLs son deliberadamente limitadas: 20 reglas por dirección por defecto, ampliables a 40, y AWS advierte que subirlas puede degradar la performance de red. Eso te dice para qué están pensadas: un bloqueo grueso a nivel de subnet, no una política de aplicación.
El marco de decisión que aguanta producción: security groups para todo, referenciando otros security groups siempre que se pueda. NACLs solo para un deny de trazo ancho que tenga que valer aunque alguien cambie un security group —un CIDR bloqueado, un aislamiento de compliance. Si estás escribiendo reglas de retorno para puertos efímeros en una NACL, estás usando la herramienta equivocada.
Dos detalles de la documentación que muerden: al NAT gateway no se le puede asociar un security group, y usa los puertos 1024 a 65535, así que cualquier NACL en su subnet tiene que dejar pasar ese rango.
Acá se cierra el hilo económico. Una NACL que corta el tráfico de retorno no bloquea limpio: no manda un reset, descarta el paquete. El cliente no ve un error, ve un timeout. Los timeouts disparan reintentos, y cada reintento hacia un servicio externo son bytes nuevos que vuelven a salir por el NAT gateway y se vuelven a cobrar a USD 0,135 por GB de punta a punta. Una regla de seguridad mal escrita no solo rompe: multiplica la línea de NatGateway-Bytes en proporción a la política de reintentos del cliente, que casi siempre es exponencial. Ese es el mecanismo por el que un incidente de red aparece en la factura del mes siguiente.
Cómo averiguás a dónde se van los gigabytes
Antes de optimizar, medí. Tres fuentes, en orden de costo.
CloudWatch, gratis y ya está prendido. El NAT gateway publica BytesInFromSource, BytesOutToDestination, BytesInFromDestination y BytesOutToSource cada minuto, con retención de 15 meses. Los regional NAT gateways agregan la dimensión AvailabilityZone, así que podés ver el desbalance entre zonas sin instrumentar nada. ErrorPortAllocation es la métrica que delata el techo de 55.000 conexiones.
Cost Explorer y el Cost and Usage Report, filtrados por usage type. Estos son los strings exactos como aparecen en la consola para us-east-1. En otra región cambia el prefijo.
| Usage type | Qué mide | Precio unitario |
|---|---|---|
USE1-NatGateway-Hours | horas de NAT gateway disponibles | USD 0,045 / hora |
USE1-NatGateway-Bytes | GB procesados por el NAT | USD 0,045 / GB |
USE1-DataTransfer-Regional-Bytes | cross-AZ, una línea por punta | USD 0,01 / GB |
DataTransfer-Out-Bytes | egress a internet | USD 0,09 / GB |
USE1-VpcEndpoint-Hours | horas de ENI de interface endpoint | USD 0,01 / hora |
USE1-VpcEndpoint-Bytes | GB por interface endpoint | USD 0,01 / GB |
PublicIPv4:InUseAddress | IPv4 pública asociada | USD 0,005 / hora |
PublicIPv4:IdleAddress | IPv4 pública sin asociar | USD 0,005 / hora |
Desde Cost Explorer, agrupar por usage type sobre el servicio EC2 - Other alcanza para ver el reparto en dos clics:
aws ce get-cost-and-usage \
--time-period Start=2026-07-01,End=2026-08-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=USAGE_TYPE \
--filter '{"Dimensions":{"Key":"SERVICE","Values":["EC2 - Other"]}}'
Sobre el CUR en Athena sale el ranking en dólares, con la porción de NAT aislada en su propia columna:
SELECT
line_item_usage_type AS usage_type,
ROUND(SUM(line_item_usage_amount), 2) AS unidades,
ROUND(SUM(line_item_unblended_cost), 2) AS usd,
ROUND(SUM(CASE WHEN line_item_usage_type LIKE '%NatGateway%'
THEN line_item_unblended_cost ELSE 0 END), 2) AS usd_nat
FROM cur_db.cost_and_usage
WHERE year = '2026' AND month = '7'
AND ( line_item_usage_type LIKE '%NatGateway%'
OR line_item_usage_type LIKE '%DataTransfer%'
OR line_item_usage_type LIKE '%VpcEndpoint%'
OR line_item_usage_type LIKE '%PublicIPv4%')
GROUP BY line_item_usage_type
ORDER BY usd DESC;
VPC Flow Logs, que no son gratis. Se facturan como vended logs, y la tarifa depende del destino: USD 0,50 por GB entregados a CloudWatch Logs y USD 0,25 por GB entregados a S3, en ambos casos en el primer tramo de 10 TB en us-east-1, más el almacenamiento del destino. Entregarlos a S3 en Parquet y consultarlos con Athena cuesta la mitad del ingest y evita el storage caro de CloudWatch Logs — por eso es la opción por defecto para este trabajo.
Lo que hace útiles a los flow logs para atribuir costo son los campos del formato custom, no el default. La versión 11 agrega interface-type, que toma los valores nat_gateway y regional_nat_gateway, y next-hop-az-id, que dice a qué AZ salió el paquete. Con esos dos campos el cross-AZ se atribuye sin correlacionar nada a mano. El tercero es traffic-path, que dice por dónde salió el tráfico:
traffic-path | Significado | Qué implica en la factura |
|---|---|---|
| 1 | otro recurso de la misma VPC | no cruza límite facturado |
| 7 | gateway VPC endpoint | gratis: ese byte no pasó por el NAT |
| 8 | internet gateway | egress a USD 0,09 por GB |
Sumar bytes agrupando por pkt-dst-aws-service y traffic-path responde la pregunta que Cost Explorer no puede: qué workload se come los GB del NAT, y cuántos de esos GB tenían un endpoint disponible. Prendelos con un objetivo y una fecha de apagado.
Las herramientas que valen el tiempo
| Herramienta | Cuándo | Costo |
|---|---|---|
| AWS Pricing Calculator | antes de escribir el código: comparar un NAT compartido contra uno por AZ contra NAT más endpoints | gratis |
| Cost Explorer | cuando la factura ya llegó: separar horas de GB por usage type | consola sin cargo, API por request |
| VPC Flow Logs con Athena | atribuir los GB del NAT a un workload concreto | ingest de vended logs, storage y datos escaneados |
| VPC Reachability Analyzer | cuando un paquete no llega y no sabés si es ruteo, SG o NACL | por análisis ejecutado |
| Infracost | en el pull request, para que el delta mensual del NAT aparezca antes del merge | open source |
| Steampipe, plugin de AWS | auditorías de una línea: NAT huérfanos, subnets sin gateway endpoint de S3 | open source |
La consulta que conviene tener guardada es la de Steampipe, porque es la que encuentra el modo de falla silencioso del gateway endpoint sin abrir la consola:
select vpc_id, service_name, route_table_ids
from aws_vpc_endpoint
where vpc_endpoint_type = 'Gateway'
and jsonb_array_length(route_table_ids) = 0;
Para las cuentas de desarrollo, donde se acumulan NAT gateways de experimentos terminados, aws-nuke limpia por configuración y es más barato que la disciplina.
El marco, en cuatro preguntas
Antes de aprobar un diseño de red, cuatro preguntas con respuesta numérica:
- ¿Cuántos GB por mes van a salir de subnets privadas, y hacia dónde? Si el destino es S3 o DynamoDB, gateway endpoint y el costo es cero —y verificá la ruta al prefix list, no la existencia del endpoint. Si es otro servicio de AWS con más de 626 GB mensuales en tres AZs, interface endpoint. Si es internet abierto, presupuestá USD 0,135 por GB.
- ¿Cuántos NAT gateways? Uno es USD 32,85 al mes y un single point of failure zonal. Tres son USD 98,55 y eliminan el cross-AZ. El breakeven está en 3.285 GB mensuales de tránsito entre zonas.
- ¿Qué necesita realmente estar en una subnet pública? Cada IPv4 pública son USD 3,65 mensuales —esté en uso o esté ociosa— y una superficie de ataque. La respuesta correcta casi siempre es "el load balancer".
- ¿Alguna regla depende de una NACL para funcionar? Si la respuesta es sí, revisá el tráfico de retorno antes de que lo revise un incidente, y antes de que los reintentos lo facturen.
Ninguna de estas cuentas requiere más que una calculadora. Que se hagan tarde, con la factura del mes ya cerrada, es lo que las vuelve caras.
Para seguir
Lecturas
- Pricing for NAT gateways — Amazon VPC User Guide — la fuente oficial del cobro doble por hora y por GB, con las dos mitigaciones que AWS mismo recomienda: NAT por AZ y VPC endpoints.
- Compare security groups and network ACLs — Amazon VPC User Guide — la tabla comparativa oficial: nivel de operación, tipo de regla, orden de evaluación y tráfico de retorno, sin blogs que la parafrasean mal.
- Overview of Data Transfer Costs for Common Architectures — el mapa de la factura fantasma: qué cruce de frontera se cobra, cuál no, y por qué el patrón NAT gateway cuesta lo que el internet gateway no.
- Save by Using Anything Other Than a NAT Gateway — la aritmética con tres escenarios medidos, incluido el de 500 GB de logs a un SaaS que cuestan 22,50 USD por NAT contra 5 por endpoint.
- Reducing our NAT Gateway cost with private networking between AWS and GCP — el contrapeso: el equipo de ingeniería de Monzo saca el tráfico cross-cloud del NAT con private networking, no con un VPC endpoint.
- Analyzing VPC Flow Logs to Reduce NAT Gateway Costs — el puente entre diagnóstico y acción: flow logs a S3 en Parquet, atribución por destino, y el hallazgo de los 13 GB que subía un profiler.
Videos
- AWS re:Invent 2025 — Advanced VPC design and new capabilities (NET340) — la charla canónica de diseño de VPC en su edición más reciente: subnets, ruteo y las capacidades nuevas del año.
- AWS re:Invent 2025 — AWS Networking Fundamentals (NET208) — nivel 200, la puerta de entrada si los fundamentos todavía no están firmes: conectividad, seguridad por capas y escalamiento.
- AWS Supports You: Monitoring and Optimizing Your Data Transfer Costs — casi la única sesión seria sobre costos de transferencia: donde viven el cargo por GB del NAT y el cross-AZ.