Lab 44 — Rede privada de verdade: o NAT que você não precisa
O problema, e a empresa que o tem
A Cadência resolveu, um por um, os problemas do L01 ao L17: rede privada de verdade (L02), deploy sem indisponibilidade (L03), segredo fora do código (L04), upload direto ao S3 (L17). Cada um desses laboratórios acrescentou tráfego que sai da sub-rede privada — e todo ele, hoje, sai pelo mesmo NAT Gateway que o L02 criou.
No fechamento trimestral, o time de duas pessoas olhou a fatura da AWS pela primeira vez linha a linha. O NAT Gateway era a terceira maior linha, atrás só de Fargate e RDS — maior que o próprio ECR, maior que o Secrets Manager, maior que o CloudWatch Logs. Nenhum desses três serviços aparece separado na fatura como "tráfego de rede": o custo está escondido dentro da conta do NAT, como GB processado.
A pergunta que motivou este laboratório não foi "como reduzir o NAT" — foi "para onde esse tráfego realmente vai". A resposta, depois de uma semana de Flow Logs: cem por cento para S3, ECR, Secrets Manager e CloudWatch Logs. Nenhum byte para um destino verdadeiramente fora da AWS.
O que este laboratório NÃO é
Não é "sempre remova o NAT". A decisão inteira depende de uma medição prévia — se a Cadência tivesse uma integração com um gateway de pagamento externo, por exemplo, o NAT continuaria necessário para esse único destino, e a pergunta mudaria para "vale a pena manter um NAT para um destino só". O laboratório ensina o mecanismo; a decisão de remover ou não depende do que a SUA medição mostrar.
O que você vai conseguir fazer
Objetivos verificáveis: cada um se prova com um comando na seção de implantação, não com a sensação de ter entendido a diferença entre os dois tipos de endpoint.
- Explicar por que Gateway endpoint e Interface endpoint não são o mesmo mecanismo com nome diferente — um usa PrivateLink, o outro não.
- Provar, com `dig` de dentro da task, que o DNS privado faz um hostname público resolver para um IP privado, sem mudar o código da aplicação.
- Associar um Gateway endpoint a uma tabela de rotas e explicar por que ele não cria ENI.
- Criar endpoints de interface para ECR, Secrets Manager e CloudWatch Logs, com security group e política restrita.
- Medir, por Flow Logs ou métrica do NAT, se resta tráfego genuinamente externo antes de decidir remover o NAT.
- Remover o NAT Gateway e o Elastic IP, e confirmar que a tabela de rotas privada não tem mais rota padrão nenhuma.
- Escrever uma política de endpoint que restrinja o Gateway endpoint do S3 a um único bucket, evitando o alcance a bucket de outra conta.
- Diagnosticar o sintoma de DNS privado esquecido, e distingui-lo de security group bloqueando a ENI.
O que a certificação cobra disto
| Conceito | Certificação | Como aparece aqui | O que dominar |
|---|---|---|---|
| Gateway endpoint | SAA-C03, SOA-C02, SAP-C02 | entrada de rota para o prefixo do S3, sem ENI | que ele só serve S3 e DynamoDB, e não usa AWS PrivateLink |
| Interface endpoint / PrivateLink | SAA-C03, SAP-C02, ANS-C01 | ENI por sub-rede habilitada, para os demais serviços | que ele É cobrado, por hora, por AZ, mais GB — não é gratuito como o Gateway |
| DNS privado do endpoint | SAA-C03, DVA-C02 | zona hospedada privada que reescreve a resolução do hostname público | que sem ele o código não muda de rota sozinho, e a chamada falha sem NAT |
| Correspondência mais específica de rota | SAA-C03, SAP-C02 | a rota do prefixo do S3 vence o antigo 0.0.0.0/0 | que rotas mais específicas sempre vencem, independente da ordem de criação |
| Política de endpoint | SAP-C02, SCS-C02 | restrição do Gateway endpoint a um bucket, e do Interface ao segredo específico | que a política padrão libera tudo, e por que isso é um risco de exfiltração |
| Security group de endpoint de interface | SAA-C03 | regra própria liberando 443 a partir do security group da task | que o endpoint tem security group dele mesmo — o NAT nunca teve |
| Custo de NAT vs PrivateLink | SAP-C02, FinOps | a comparação de gigabyte contra hora-AZ mais gigabyte | que abaixo de certo volume o Interface endpoint pode custar MAIS que o NAT |
Onde isto costuma ser cobrado errado
A pergunta clássica descreve uma sub-rede privada precisando alcançar o S3 "sem NAT Gateway e sem tráfego passando pela internet" e pede a solução mais barata. O distrator mais forte é "criar um Interface endpoint para o S3" — que funciona, mas cobra por hora e por GB quando existe uma opção gratuita para exatamente esse serviço. Quem lembra que S3 e DynamoDB têm Gateway endpoint acerta sem hesitar.
Requisitos, e como cada um muda o desenho
Nenhum requisito aqui pede um recurso novo por adorno. Cada linha decide qual tipo de endpoint entra e onde.
| Requisito | Valor declarado | O que ele decide no desenho |
|---|---|---|
| Tráfego para S3 sem custo adicional | obrigatório | Gateway endpoint — é o único mecanismo gratuito disponível para esse destino |
| ECR, Secrets Manager e Logs sem sair da AWS | obrigatório | quatro endpoints de interface: dois para o ECR (api e dkr), um para Secrets Manager, um para Logs — mais o ssmmessages, obrigatório à parte para o ECS Exec continuar funcionando sem NAT |
| Zero mudança de código da aplicação | obrigatório | DNS privado habilitado em cada endpoint de interface — sem isso, o requisito falha |
| NAT removido só se seguro | condicional | medição de Flow Logs por duas semanas antes de qualquer `terraform destroy` |
| Nenhum bucket de outra conta alcançável | segurança | política de endpoint do Gateway restrita ao ARN do bucket de laudos |
| Disponibilidade em duas AZs | já declarado desde o L02 | cada endpoint de interface habilitado nas duas sub-redes privadas, não só numa |
| Rastreabilidade da mudança | operacional | medição do GB processado pelo NAT antes e depois, documentada e não apenas assumida |
A hipótese sustenta a arquitetura inteira, e ela tem prazo de validade
Todo o desenho de produção deste laboratório depende de "não sobra tráfego genuinamente externo". No dia em que a Cadência integrar um gateway de pagamento ou qualquer API de terceiro, essa hipótese deixa de valer, e a pergunta muda de "remover o NAT" para "manter um caminho de saída só para esse destino novo". Revisite a hipótese a cada integração externa nova, não só uma vez.
Arquitetura mínima: o estado que o L02 deixou
Este não é um desenho a construir — é o estado atual da Cadência, herdado do L02. Ele funciona bem, e é exatamente por isso que o defeito passa despercebido: nada está quebrado, só está caro sem necessidade.
- → HTTPS 443
- → encaminha para a task
- → saída padrão: 0.0.0.0/0 → NAT, para qualquer destino
- → traduz para o endereço de saída fixo
- → export diário de laudo (L17)
- → pull de imagem a cada deploy (L03)
- → leitura da credencial (L04)
- → envio de log de cada task
- Fora da AWS
- Rede e entrega
- Compute
- Armazenamento
- Segurança e identidade
- Gestão e governança
Este é o desenho que o L02 deixou, e ele funciona: a sub-rede privada tem uma rota padrão para o NAT, e o NAT resolve qualquer saída. O defeito não é nenhuma linha errada — é que a MESMA rota atende tráfego para fora da AWS e tráfego para dentro dela, e o NAT cobra os dois pelo mesmo preço. Percorra os passos: cada serviço que a Cadência já usa está, hoje, pagando pedágio.
- Uma linha cobre quatro destinos diferentes. A tabela de rotas da sub-rede privada tem uma única entrada — 0.0.0.0/0 → NAT — e ela não distingue "chamada a um fornecedor de fora" de "chamada a outro serviço da própria conta AWS". As duas saem pelo mesmo lugar.
- O NAT não sabe que o destino é da AWS. Ele é um tradutor de endereço: troca o IP de origem da task pelo Elastic IP e mantém a tabela de conexões para a resposta voltar. Do ponto de vista dele, uma chamada ao S3 e uma chamada a um site qualquer são o mesmo tipo de pacote.
- O S3 leva o laudo de garantia, do L17. Cada upload processado pela aplicação grava o resultado no bucket — tráfego que nunca sai fisicamente da rede da AWS, mas que estruturalmente atravessa o NAT e é cobrado por gigabyte processado, nos dois sentidos.
- O ECR leva a imagem, a cada deploy do L03. O rolling update do L03 puxa uma imagem inteira por task nova. Multiplicado pela frequência de deploy que o próprio L03 tornou possível, é o segundo maior consumidor de GB processado pelo NAT — e cresce junto com a velocidade de entrega.
- O Secrets Manager leva a credencial, do L04. Toda vez que uma task nasce — em deploy, em escala automática, em substituição depois de falha — ela lê a credencial do banco pelo mesmo caminho. É tráfego pequeno em bytes, mas ele soma ao mesmo NAT que os demais.
- O CloudWatch Logs leva cada linha, o tempo todo. Diferente dos anteriores, este não é um evento: é um fluxo contínuo. Em volume de log alto, ele é frequentemente o maior consumidor silencioso de GB processado, porque ninguém pensa em "logging" como tráfego de rede.
O NAT em si não fez nada errado
Ele foi o desenho certo no L02, quando a alternativa era o banco publicamente acessível. O que mudou não foi o NAT — foi o volume de tráfego para dentro da própria AWS crescendo junto com o produto: mais deploys (L03), mais uploads (L17), mais log. Um mecanismo correto ontem pode deixar de ser o mais barato hoje, sem que ninguém tenha decidido errado em nenhum momento.
Arquitetura para produção: sem NAT
Cada peça nova abaixo rastreia a uma linha da tabela de requisitos. A diferença estrutural em relação ao desenho anterior não é um endpoint a mais ao lado do NAT — é a AUSÊNCIA do NAT, porque nada do que restou precisa dele.
- → HTTPS 443, sem mudança para quem usa a API
- → encaminha para o IP privado da task
- → toda saída passa pela tabela antes de qualquer decisão
- → prefixo do S3 vence o antigo catch-all, por especificidade
- → entrega ao serviço, sem ENI e sem cobrança
- → pull de imagem: o hostname de sempre resolve para a ENI
- → download da camada, dentro da rede da AWS
- → GetSecretValue, sem mudar uma linha da aplicação
- → leitura da credencial do banco
- → PutLogEvents a cada linha emitida
- → grava o log, pela ENI
- Fora da AWS
- Rede e entrega
- Compute
- Armazenamento
- Segurança e identidade
- Gestão e governança
O NAT não perde uma função — ele deixa de existir, porque nada do que sobrou precisa dele. O S3 é alcançado por uma entrada na tabela de rotas, sem ENI. Os outros três ganham uma ENI cada, e o DNS privado faz o código não notar a diferença. Percorra os passos: a mudança estrutural é a AUSÊNCIA do NAT no desenho, não uma peça a mais ao lado dele.
- A rota do S3 não tem mais hop nenhum. A tabela de rotas ganha uma entrada cujo destino é o prefixo gerenciado pela AWS para o S3 na região, e cujo alvo é o próprio Gateway endpoint. Por correspondência mais específica, ela vence qualquer 0.0.0.0/0 remanescente.
- O Gateway endpoint é a rota, não um recurso a mais. Não existe ENI aqui, não existe security group do lado do endpoint, e não existe cobrança. É por isso que ele não aparece na fatura de PrivateLink: tecnicamente, ele nem usa PrivateLink — é um mecanismo de roteamento separado.
- O DNS passou a responder de dentro. Com o DNS privado habilitado, a AWS cria uma zona hospedada privada que faz o hostname público de sempre — o mesmo que o SDK já chamava — resolver para o IP privado da ENI do endpoint. Nenhuma linha de configuração de conexão mudou.
- Cada interface endpoint é uma ENI, com hora e GB cobrados. Diferente do Gateway, o Interface endpoint É um recurso: uma interface de rede por sub-rede habilitada, cobrada por hora ligada em cada zona de disponibilidade, mais gigabyte processado. É uma conta previsível, não gratuita.
- O NAT saiu do desenho porque não sobrou tráfego genuinamente externo. Depois de medir o que passava pelo NAT antes da migração, a Cadência não encontrou nenhum destino fora da AWS — só os quatro serviços agora atendidos por endpoint. Sem tráfego para justificá-lo, o NAT e o Elastic IP foram removidos.
- O security group da ENI é a fronteira nova. Cada endpoint de interface tem o seu próprio security group, e ele precisa liberar a porta 443 para o security group da task explicitamente — senão o DNS resolve certo e a conexão é recusada mesmo assim, um sintoma que engana.
O ganho que não é só custo
Tráfego que passa por um endpoint nunca atravessa o Internet Gateway, mesmo estruturalmente. Isso reduz a superfície de rede da aplicação — menos caminho para um Flow Log precisar explicar em uma auditoria — e é um benefício que fica mesmo se, no seu caso, o cálculo de custo desse empate com o NAT.
Como a resolução de nome muda, ponta a ponta
O mecanismo inteiro deste laboratório vive numa única pergunta: quando o código chama um hostname público que ele sempre chamou, para onde o DNS manda essa consulta? A resposta muda com o endpoint, e o código nunca fica sabendo.
A pegadinha que faz o laboratório inteiro parecer não funcionar
Criar o endpoint sem marcar `private_dns_enabled = true` é o erro mais caro deste módulo. O endpoint fica `available`, a ENI existe, e nada muda: o hostname público continua resolvendo para o IP público de sempre, porque só o DNS privado reescreve essa resolução. Sem NAT no ar, a chamada simplesmente para de funcionar — e o sintoma ("não consigo mais ler o segredo") aponta para tudo, menos para essa uma linha.
A ordem importa na prática: habilite o DNS privado do endpoint e confirme a resolução com dig ANTES de remover o NAT. Assim, se algo estiver errado, a aplicação ainda tem o caminho antigo funcionando enquanto você corrige.
Um registro de Flow Log real, depois da migração: origem e destino são os DOIS privados. Antes do endpoint, o dstaddr desta mesma chamada seria o IP da interface do NAT, e o pacote teria um segundo salto ate o IGW.
{
"version": 2,
"account-id": "111122223333",
"interface-id": "eni-0f7a2b9c1d3e4f567",
"srcaddr": "10.0.32.14",
"dstaddr": "10.0.32.201",
"srcport": 51224,
"dstport": 443,
"protocol": 6,
"packets": 12,
"bytes": 3140,
"start": 1754524800,
"end": 1754524860,
"action": "ACCEPT",
"log-status": "OK"
}As decisões, e o que se perde em cada uma
📋 Reduzir a fatura de rede de uma equipe de duas pessoas, cujo tráfego de saída — medido por Flow Logs durante duas semanas — é 100% dirigido a S3, ECR, Secrets Manager e CloudWatch Logs, sem nenhum destino verdadeiramente externo à AWS.
A medição prévia é o que sustenta a decisão: sem ela, remover o NAT seria aposta, não engenharia. Com ela, cada gigabyte que hoje passa pelo NAT tem um endpoint correspondente que o atende sem sair da rede da AWS — de graça no caso do S3, por hora e GB nos outros três. A soma das horas de três ENIs em duas AZs é, para o volume medido da Cadência, menor que a conta atual do NAT — e o ganho de segurança (tráfego que nunca atravessa a fronteira pública) vem junto, sem custo adicional.
Alt: Manter o NAT como está — continua funcionando e não exige nenhuma mudança — mas cobra pedágio sobre tráfego que nunca precisou sair da AWS, para sempre, crescendo com o produto
Alt: NAT Gateway por AZ — resolve dependência de zona, não custo — dobra a parte fixa sem tocar no problema real, que é o tipo de tráfego, não a topologia do NAT
Alt: Proxy HTTP centralizado numa conta de rede compartilhada — é o desenho certo quando várias contas dividem saída — over-engineering para uma equipe de duas pessoas com uma VPC só; é conversa do L45 em diante
Alt: Endpoint para todo serviço que a AWS oferece, por precaução — troca o pedágio do NAT por hora de ENI parada sem tráfego — o oposto de economizar; endpoint sem volume medido é a mesma aposta ao contrário
| Decisão | Escolha | Alternativas | Motivo | O que se perde |
|---|---|---|---|---|
| Endpoint do S3 | Gateway | Interface endpoint para o S3 (também suportado) | é gratuito e S3 suporta os dois; não há razão para pagar pelo mesmo destino | nada relevante — o Gateway cobre o caso de uso por inteiro |
| Endpoint do ECR | dois Interface (api + dkr) | só o `dkr`, assumindo que o `api` não é chamado | a autenticação usa o `api`; faltando ele, o pull falha antes de baixar qualquer camada | duas ENIs por AZ em vez de uma — dobro do custo fixo deste serviço |
| Habilitação por AZ | as duas sub-redes privadas | só a AZ a, mais barato | o requisito de disponibilidade de duas AZs, herdado do L02, não é negociável aqui | dobra a parte fixa de cada endpoint de interface |
| Remoção do NAT | total, depois de medir | manter "por garantia" | sem tráfego que o justifique, manter é pagar por um recurso comprovadamente ocioso | perde-se a saída genérica: qualquer destino externo NOVO no futuro exige revisitar isto |
| Política do Gateway endpoint | restrita ao bucket de laudos | política padrão (libera tudo) | evita que o mesmo endpoint alcance bucket de outra conta AWS | qualquer bucket novo da própria Cadência precisa ser adicionado à política |
Construir: o Gateway endpoint para o S3
É o único recurso deste laboratório que reduz custo em vez de trocar uma cobrança por outra. Repare no que ele NÃO tem: nenhum `subnet_ids`, porque ele não cria interface de rede — ele se associa a tabelas de rotas inteiras.
# s3-gateway-endpoint.tf — a rota que substitui o hop, e a política que evita vazamento
# Sem interface de rede, sem security group do lado do endpoint, sem cobrança.
# O que este recurso FAZ é adicionar uma entrada na(s) tabela(s) de rotas
# listadas em `route_table_ids`: destino = prefixo gerenciado do S3 na região,
# alvo = este endpoint.
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.principal.id
service_name = "com.amazonaws.${var.regiao}.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = [aws_route_table.privada.id]
# A política padrão de um VPC endpoint libera QUALQUER ação, de QUALQUER
# principal, sobre QUALQUER recurso. Isso significa que, sem restringir aqui,
# uma task comprometida alcança o bucket de QUALQUER conta AWS através do
# mesmo endpoint criado para o bucket da Cadência — porque a rota vale para
# todo tráfego destinado ao S3 na região, não só para o seu bucket.
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = "*"
Action = ["s3:GetObject", "s3:PutObject", "s3:ListBucket"]
# Restrito ao ARN do bucket de laudos do L17. Qualquer outro bucket,
# inclusive de outra conta AWS, fica fora do que este endpoint permite.
Resource = [
aws_s3_bucket.laudos.arn,
"${aws_s3_bucket.laudos.arn}/*",
]
}]
})
}
# O security group da TASK precisa liberar saída para o prefixo do S3 na porta
# 443 — o endpoint não tem security group próprio para isso. Sem esta regra, a
# rota existe e o pacote não sai da task mesmo assim.
data "aws_ec2_managed_prefix_list" "s3" {
name = "com.amazonaws.${var.regiao}.s3"
}
resource "aws_vpc_security_group_egress_rule" "task_para_s3" {
security_group_id = aws_security_group.task.id
prefix_list_id = data.aws_ec2_managed_prefix_list.s3.id
from_port = 443
to_port = 443
ip_protocol = "tcp"
description = "S3 via gateway endpoint — NACL nao aceita prefix list, so security group"
}
A política padrão é a porta destrancada mais barata da AWS
Sem restringir `policy`, o Gateway endpoint libera qualquer ação de qualquer principal sobre qualquer recurso do S3 na região — incluindo buckets de OUTRAS contas AWS, porque a rota vale para todo tráfego destinado ao serviço, não só ao seu bucket. É um vetor de exfiltração de dado documentado: uma task comprometida usa o endpoint que você criou para o SEU bucket para alcançar o bucket de qualquer outro lugar que aceite a credencial dela.
Construir: os endpoints de interface, e o security group que os protege
Quatro serviços, cinco endpoints — o ECR sozinho pede dois, e o ECS Exec (não é um serviço que a aplicação chama, mas uma dependência operacional do próprio laboratório) pede o quinto. Cada um cria uma ENI de verdade por sub-rede habilitada, e é por isso que eles aparecem na fatura de um jeito que o Gateway endpoint nunca aparece.
# interface-endpoints.tf — uma ENI por sub-rede habilitada, para os tres servicos restantes
# Security group PROPRIO dos endpoints. E a fronteira nova depois que o NAT
# sai do desenho: sem esta regra liberando 443 a partir do security group da
# task, o DNS resolve certo e a conexao e recusada mesmo assim.
resource "aws_security_group" "endpoints" {
name = "${var.projeto}-endpoints"
vpc_id = aws_vpc.principal.id
}
resource "aws_vpc_security_group_ingress_rule" "endpoints_da_task" {
security_group_id = aws_security_group.endpoints.id
referenced_security_group_id = aws_security_group.task.id
from_port = 443
to_port = 443
ip_protocol = "tcp"
description = "HTTPS das tasks para as ENIs dos endpoints de interface"
}
locals {
# ECR precisa de DOIS endpoints: "api" resolve chamadas de controle
# (autenticacao, describe), "dkr" resolve o pull de camada de imagem em si.
# Faltando qualquer um dos dois, o pull falha depois de autenticar.
#
# ssm_msgs e OBRIGATORIO por um motivo separado do ECR: e o que o ECS Exec
# usa para o agente SSM dentro da task alcancar o Session Manager. Sem NAT
# e sem este endpoint, "aws ecs execute-command" — usado nas provas mais
# adiante — para de funcionar depois do destroy do NAT, porque o agente
# nao tem mais rota nenhuma ate o Session Manager. Em Fargate plataforma
# 1.4.0+ isto basta; em plataformas mais antigas some tambem precisar dos
# endpoints ecs-agent e ecs-telemetry — confirme a versao da sua platform_version.
servicos_interface = {
ecr_api = "ecr.api"
ecr_dkr = "ecr.dkr"
secretos = "secretsmanager"
logs = "logs"
ssm_msgs = "ssmmessages"
}
}
resource "aws_vpc_endpoint" "interface" {
for_each = local.servicos_interface
vpc_id = aws_vpc.principal.id
service_name = "com.amazonaws.${var.regiao}.${each.value}"
vpc_endpoint_type = "Interface"
subnet_ids = [for s in aws_subnet.privada : s.id]
security_group_ids = [aws_security_group.endpoints.id]
# E ESTA linha que faz o codigo existente atravessar o endpoint sem mudar.
# Sem ela, o hostname publico de sempre continua resolvendo para o IP
# publico do servico, e sem NAT essa chamada nao tem mais rota nenhuma.
private_dns_enabled = true
tags = { Name = "${var.projeto}-vpce-${each.key}" }
}
# Politica restrita ao Secrets Manager: so o segredo do banco, so a acao de
# leitura. O padrao (liberar tudo) autorizaria a task a ler QUALQUER segredo
# da conta atraves deste endpoint, nao so o dela.
resource "aws_vpc_endpoint_policy" "secrets" {
vpc_endpoint_id = aws_vpc_endpoint.interface["secretos"].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = "*"
Action = "secretsmanager:GetSecretValue"
Resource = aws_secretsmanager_secret.banco.arn
}]
})
}
O security group do endpoint é regra nova, não herança do NAT
O NAT nunca teve security group próprio — o controle vivia só do lado da task. Um endpoint de interface tem o dele, e ele filtra de forma independente: mesmo com o security group da task liberando saída, uma ENI de endpoint sem a regra de entrada correspondente recusa a conexão. As duas pontas precisam concordar.
Construir: removendo o NAT, e o que sobra na tabela de rotas
Esta seção não é um recurso novo — é a ausência de três. O `terraform plan` depois desta mudança mostra `destroy` no NAT Gateway e no Elastic IP, e uma tabela de rotas sem nenhuma linha além da local.
# rede.tf — o que sai, e o que muda na tabela de rotas privada
# Estes tres recursos do L02 SAEM do Terraform. O `terraform plan` mostra os
# tres como destroy — e SO faz sentido rodar isto depois de confirmar, pela
# medicao de Flow Logs da secao de provas, que nao sobra trafego externo real.
#
# resource "aws_nat_gateway" "nat" { ... } # REMOVIDO
# resource "aws_eip" "nat" { ... } # REMOVIDO — Elastic IP
# # continua cobrando se
# # ficar orfao; ver limpeza
# route {
# cidr_block = "0.0.0.0/0" # REMOVIDO desta tabela
# nat_gateway_id = aws_nat_gateway.nat.id
# }
# A tabela privada do L02, depois da mudanca. Repare no que NAO existe mais:
# nenhuma linha 0.0.0.0/0. A unica rota alem da local (implicita) e a que o
# `aws_vpc_endpoint.s3` do Gateway endpoint acrescenta sozinho — voce nao
# escreve essa rota, ela vem do `route_table_ids` do recurso do endpoint.
resource "aws_route_table" "privada" {
vpc_id = aws_vpc.principal.id
tags = { Name = "${var.projeto}-rt-privada-sem-nat" }
# Nenhum `route {}` bloco aqui. A tabela nasce so com a rota local implicita
# da VPC. A rota para o S3 e injetada pelo endpoint, nao declarada aqui —
# e por isso `terraform plan` nesta tabela nao mostra diferenca nenhuma
# quando o endpoint muda, o que confunde quem espera ver a rota no arquivo.
}
# Sem NAT, nao ha mais recurso na sub-rede PUBLICA alem do ALB. Se nenhum
# outro workload precisar de saida publica de verdade, a sub-rede publica
# passa a existir so para o balanceador — e isso e uma informacao, nao um erro.
Do lado da aplicação, nada muda — é a prova de que o laboratório funcionou. O código abaixo é idêntico antes e depois; o único trecho novo é um log de diagnóstico opcional, que existe só para o laboratório medir o IP resolvido.
// Program.cs — o que NAO muda, e por que isso e a prova do laboratorio
var builder = WebApplication.CreateBuilder(args);
// As tres linhas abaixo sao IDENTICAS antes e depois deste laboratorio. O SDK
// da AWS chama o hostname publico regional de cada servico; quem decide se
// esse hostname resolve para um IP publico (via NAT) ou para a ENI de um
// endpoint de interface (via DNS privado) e a REDE, nao a aplicacao.
builder.Services.AddAWSService<IAmazonSecretsManager>();
builder.Services.AddAWSService<IAmazonS3>();
// A credencial do banco (L04) chega da mesma forma: a aplicacao pede o
// segredo pelo nome, sem saber — e sem precisar saber — se a chamada
// atravessou o NAT ou uma ENI do PrivateLink.
var segredo = await app.Services.GetRequiredService<IAmazonSecretsManager>()
.GetSecretValueAsync(new GetSecretValueRequest { SecretId = "cadencia/banco/senha" });
// O unico jeito de PROVAR que o caminho mudou, do lado da aplicacao, e medir
// o tempo de resolucao de DNS — nao o codigo de negocio. Deixamos isto como
// log de diagnostico, desligavel por configuracao, para o laboratorio: nao e
// algo que uma aplicacao de producao precisa emitir permanentemente.
if (builder.Configuration.GetValue("DIAGNOSTICO_DNS", false))
{
var sw = System.Diagnostics.Stopwatch.StartNew();
var enderecos = await System.Net.Dns.GetHostAddressesAsync(
$"secretsmanager.{builder.Configuration["AWS:Region"]}.amazonaws.com");
app.Logger.LogInformation(
"secretsmanager resolveu para {Ip} em {Ms} ms — {Tipo}",
enderecos.FirstOrDefault(), sw.ElapsedMilliseconds,
enderecos.FirstOrDefault()?.ToString().StartsWith("10.") == true ? "IP privado (endpoint)" : "IP publico (sem endpoint)");
}
var app2 = builder.Build();
app2.Run();
Implantar, e provar que a rota mudou de verdade
Cinco provas. A quarta é a mais importante e a mais fácil de pular: ela mede o NAT ANTES de apagá-lo, e é o que separa "decidimos" de "torcemos para dar certo".
#!/usr/bin/env bash
# provas.sh — cinco medicoes; a mudanca de rota se prova, nao se assume
set -euo pipefail
PROJETO=cadencia; REGIAO=us-east-1
TASK=$(aws ecs list-tasks --cluster $PROJETO --service-name api --query 'taskArns[0]' --output text)
# -- Prova 1: o hostname publico do Secrets Manager resolve para IP PRIVADO --
aws ecs execute-command --cluster $PROJETO --task "$TASK" --container api \
--interactive --command "dig +short secretsmanager.$REGIAO.amazonaws.com"
# Esperado: um IP na faixa 10.0.x.x — o IP privado da ENI do endpoint.
# Um IP publico aqui significa que private_dns_enabled esta false, ou que o
# endpoint nao existe.
# -- Prova 2: a tabela de rotas privada NAO tem 0.0.0.0/0 --
aws ec2 describe-route-tables --route-table-ids "$(terraform output -raw rt_privada_id)" \
--query 'RouteTables[0].Routes[*].DestinationCidrBlock' --output text
# Esperado: so a rota local (10.0.0.0/16) e a de prefixo do S3. Qualquer
# 0.0.0.0/0 aqui significa que o NAT nao foi removido de fato.
# -- Prova 3: o S3 responde sem NAT no ar --
aws ecs execute-command --cluster $PROJETO --task "$TASK" --container api \
--interactive --command \
"curl -s -o /dev/null -w '%{http_code}' https://cadencia-laudos.s3.$REGIAO.amazonaws.com/"
# Esperado: um codigo HTTP (403 sem credencial ja prova conectividade). Timeout
# aqui, com o NAT removido, significa que a rota do gateway endpoint nao
# esta associada a esta tabela.
# -- Prova 4: o NAT parou de processar bytes, ANTES de ser removido --
aws cloudwatch get-metric-statistics --namespace AWS/NATGateway \
--metric-name BytesOutToDestination --statistics Sum --period 3600 \
--start-time "$(date -u -d '2 hours ago' +%FT%TZ)" --end-time "$(date -u +%FT%TZ)" \
--dimensions Name=NatGatewayId,Value="$(terraform output -raw nat_gateway_id 2>/dev/null || echo none)"
# Esperado: soma proxima de zero na ultima hora, medida ANTES do destroy —
# e a evidencia de que remover o NAT nao vai quebrar trafego real.
# -- Prova 5: a politica do S3 endpoint recusa bucket de fora --
aws ecs execute-command --cluster $PROJETO --task "$TASK" --container api \
--interactive --command \
"curl -s -o /dev/null -w '%{http_code}' https://algum-bucket-de-outra-conta.s3.$REGIAO.amazonaws.com/objeto" \
&& echo "FALHA DA PROVA: a politica do endpoint deixou passar" \
|| echo "OK: a politica restrita ao bucket da Cadencia bloqueou o resto do S3"
| Prova | Comando | Resultado que aprova | O que reprova, e o que significa |
|---|---|---|---|
| 1 · DNS resolve para IP privado | `dig` de dentro da task | endereço na faixa 10.0.x.x | IP público significa DNS privado desligado, ou endpoint ausente |
| 2 · Tabela sem rota padrão | `describe-route-tables` | só a rota local e a de prefixo do S3 | 0.0.0.0/0 presente significa que o NAT não foi removido de fato |
| 3 · S3 responde sem NAT | `curl` de dentro da task | qualquer código HTTP (mesmo 403) | timeout significa que a rota do Gateway endpoint não está associada à tabela |
| 4 · NAT sem tráfego, antes do destroy | métrica `BytesOutToDestination` | soma próxima de zero na última hora | bytes ainda fluindo significa que resta tráfego não migrado — não remova ainda |
| 5 · Política do S3 endpoint restringe | `curl` a bucket de outra conta | a chamada é recusada | sucesso aqui é falha da prova: a política ficou como o padrão, que libera tudo |
A prova 4 é a que sustenta a decisão
Ela não pergunta se o desenho novo funciona — pergunta se o antigo já não estava sendo usado. É a diferença entre "parece seguro remover" e "medimos e não sobrou nada", e é a segunda que se defende numa revisão de arquitetura.
Quebrar de propósito: três falhas e o diagnóstico
| O que fazer | Sintoma | Como diagnosticar | O que a falha ensina |
|---|---|---|---|
| Criar o endpoint de interface sem `private_dns_enabled` | sem NAT, a chamada ao serviço falha por timeout; com NAT ainda no ar, "funciona" mas não usa o endpoint | `dig` do hostname público de dentro da task devolve IP público, não privado | que o DNS privado é o que faz o código atravessar o endpoint — a ENI sozinha não basta |
| Remover o NAT sem associar o Gateway endpoint à tabela certa | o S3 para de responder; os outros três serviços continuam OK se tiverem endpoint | `describe-route-tables` na tabela da sub-rede que falhou não mostra a rota de prefixo | que `route_table_ids` do endpoint precisa listar TODAS as tabelas privadas, não só uma |
| Esquecer a regra de entrada no security group dos endpoints | DNS resolve certo, mas a conexão TCP é recusada — sintoma que engana, porque parece rede | tentativa de conexão TCP direta na porta 443 do IP resolvido falha; DNS não é o problema | que o endpoint de interface tem security group PRÓPRIO, independente do da task |
A combinação que apaga dados de verdade
Remover o NAT E deixar a política do Gateway endpoint no padrão (libera tudo) ao mesmo tempo não quebra nada visível — e é justamente por isso que é a pior combinação: nada no comportamento observável avisa que o alcance a outros buckets ficou aberto. Trate a política restrita como parte do MESMO commit que cria o endpoint, nunca como um ajuste "para depois".
Uma aplicação numa sub-rede privada, sem NAT Gateway, ainda consegue ler um objeto do S3 depois que um Gateway endpoint é associado à tabela de rotas dessa sub-rede. Por que isso funciona sem nenhuma interface de rede nova?
Segurança: o que muda quando o tráfego para de sair da VPC
Tirar tráfego da internet reduz uma classe de risco e desloca outra: a superfície deixa de ser "alguém interceptando pacote na borda" e passa a ser "o próprio endpoint alcançando mais do que devia".
| Risco | Probabilidade | Impacto | Controle preventivo | Detecção | Resposta |
|---|---|---|---|---|---|
| Exfiltração via Gateway endpoint sem política restrita | média | crítico | política do endpoint limitada ao ARN do bucket próprio | CloudTrail em `GetObject`/`PutObject` com bucket fora da lista esperada | restringir a política; girar credenciais da task se houve alcance indevido |
| Interface endpoint sem DNS privado, tráfego volta ao público em silêncio | média | médio | checagem de `private_dns_enabled = true` na revisão do Terraform | prova 1 (dig) na esteira de CI; sem isso, ninguém percebe até o NAT ser removido | habilitar o DNS privado; validar de novo antes de remover o NAT |
| Security group do endpoint liberado para além da task | baixa | médio | ingress só do security group da task, nunca de faixa de IP | IAM Access Analyzer / revisão periódica das regras do SG de endpoints | restringir a regra ao SG correto |
| NAT removido com tráfego externo residual não medido | média | alto | medição de Flow Logs por pelo menos duas semanas antes do destroy | alarme de erro de conexão na aplicação logo após a remoção | recriar o NAT rapidamente; ele não deixa estado, só volta a existir |
| Elastic IP órfão depois do destroy do NAT | alta | baixo, e permanente | EIP declarado no mesmo Terraform do NAT, removido junto | Cost Explorer mostra cobrança de endereço não associado | liberar o endereço manualmente se sobrar |
O `Principal = "*"` que aparece nas políticas de endpoint acima
Diferente do `Resource: "*"` em IAM, aqui o `*` no `Principal` é o padrão normal — a política de endpoint não substitui a policy de IAM da task, ela ACRESCENTA uma segunda checagem. O `Resource` restrito ao bucket ou ao segredo específico é o que faz o trabalho de segurança; o `Principal = "*"` só diz "qualquer identidade que já tenha permissão de IAM pode usar este endpoint", o que é o comportamento esperado.
Observabilidade: as perguntas que o painel tem de responder
| Pergunta | Métrica ou consulta | O que significa mudar | Limiar inicial |
|---|---|---|---|
| O NAT ainda processa algum byte? | `BytesOutToDestination` do NAT | qualquer valor acima de zero é tráfego não migrado, ou destino externo real | zero por 2 semanas antes de considerar remover |
| O endpoint de interface está saudável? | estado do endpoint via `describe-vpc-endpoints` | `available` é o único estado que atende tráfego | qualquer estado diferente por mais de alguns minutos |
| O DNS está resolvendo para dentro? | consulta periódica de `dig` a partir de uma task | IP público de volta indica DNS privado desabilitado ou endpoint removido | qualquer resposta fora da faixa privada da VPC |
| O Gateway endpoint está alcançando bucket inesperado? | CloudTrail `GetObject`/`PutObject` | bucket fora do ARN esperado é sinal de política aberta demais | qualquer chamada a bucket fora da lista |
| Quanto cada endpoint de interface processa? | métrica de bytes por VPC endpoint | endpoint com volume baixo pode custar mais em hora parada que gerava em GB no NAT | revisar mensalmente contra o volume do NAT antigo |
O NAT não avisa quando fica ocioso
Diferente de uma instância parada, um NAT Gateway sem tráfego continua com aparência normal no console — disponível, saudável, sem alarme nenhum. A única forma de saber que ele não tem mais função é olhar a métrica de bytes de propósito, o que raramente entra em painel algum até alguém perguntar pela fatura.
Escala: 10, 10 mil, 1 milhão
| Volume | O que acontece com os endpoints | O que passa a doer | O que fazer |
|---|---|---|---|
| 10 requisições/dia ao Secrets Manager | endpoint de interface ocioso a maior parte do tempo | a hora-AZ do endpoint pode custar mais que o GB que esse tráfego gerava no NAT | medir antes: nem todo serviço de baixo volume compensa endpoint próprio |
| Centenas de deploys/dia pelo ECR | os dois endpoints do ECR processam GB proporcional aos pulls | volume alto de pull é onde o Interface endpoint mais se paga frente ao NAT | nada — é o caso de uso ideal do endpoint de interface |
| Log em volume alto pelo CloudWatch Logs | o endpoint de logs concentra a maior parte do GB processado | ele tende a ser, sozinho, maior que os outros três somados | considerar amostragem ou retenção mais curta antes de otimizar o transporte |
| Múltiplas VPCs precisando dos mesmos endpoints | cada VPC precisa do seu próprio conjunto | endpoint não é compartilhável entre VPCs sem peering ou Transit Gateway | centralizar numa conta de rede compartilhada — é o L45 |
| Falha de uma AZ | a ENI daquela AZ some; a outra AZ continua respondendo | com endpoint em uma AZ só, a outra fica sem acesso ao serviço | sempre as duas AZs — é o mesmo requisito de disponibilidade do L02 |
O limite que raramente aparece na teoria e existe na prática
Endpoints de interface têm limite de largura de banda por ENI, documentado por serviço. Para a maioria das cargas de ECR, Secrets Manager e Logs de uma aplicação de porte médio isso nunca é alcançado — mas é uma dimensão real de escala que o Gateway endpoint, sem ENI, simplesmente não tem.
Custo: o que este laboratório troca por o quê
É o primeiro laboratório da série em que a arquitetura de produção custa MENOS que a mínima, no volume medido da Cadência. Isso não é garantido para todo mundo — depende do quanto cada serviço é chamado.
| Cenário | Volume | O que muda na fatura | Tendência |
|---|---|---|---|
| Protótipo | poucas chamadas por dia a cada serviço | os quatro Interface endpoints, por hora-AZ, podem custar mais que o GB que geravam no NAT | considerar manter o NAT até o volume justificar os endpoints |
| Produção pequena (Cadência hoje) | deploys diários, uploads diários, log contínuo | a soma das horas-AZ dos quatro endpoints fica abaixo da conta atual do NAT | queda visível já no primeiro mês |
| Alta escala | dezenas de deploys/dia, log em volume alto | o GB processado pelos endpoints de interface cresce, mas sem a parte fixa do NAT crescer junto — e o S3 continua de graça | a vantagem dos endpoints aumenta com o volume, não diminui |
| Dimensão | Cobra por | Cuidado |
|---|---|---|
| Gateway endpoint (S3) | nada | única linha desta tabela sem custo — é por isso que ele entra sempre que o serviço suporta |
| Interface endpoint | hora ligada por AZ habilitada, mais GB processado | a parte fixa corre mesmo sem tráfego — não crie endpoint para serviço não medido |
| NAT Gateway removido | deixa de cobrar hora e GB | o Elastic IP associado a ele precisa ser liberado à parte, ou continua cobrando sozinho |
| Transferência entre AZs | GB entre zonas, independente de endpoint | endpoint não elimina custo de tráfego cross-AZ que já existia por outro motivo |
A economia que só aparece se alguém medir
Sem a prova 4 (bytes do NAT antes do destroy), a decisão de remover vira aposta. Com ela, a Cadência tem o número exato de quanto o NAT processava — e o mesmo número, comparado à soma das horas-AZ dos endpoints, é o que sustenta a decisão numa revisão de orçamento, não só na intuição de que "deve ser mais barato".
Well-Architected nos seis pilares
| Pilar | Situação ao fim deste laboratório | Risco que fica | Melhoria | Prioridade |
|---|---|---|---|---|
| Excelência operacional | rota documentada, com prova de que o NAT não tinha mais tráfego antes de sair | endpoint novo esquecido de private DNS em serviço futuro | checklist de revisão de Terraform cobrando `private_dns_enabled` | média |
| Segurança | tráfego para dentro da AWS nunca atravessa a fronteira pública; políticas restritas | ainda existe um `Principal = "*"` nas políticas de endpoint, aceitável mas revisável | condição `aws:SourceVpce` na policy do bucket, do outro lado | média |
| Confiabilidade | dois endpoints por serviço, um por AZ, mesmo requisito do L02 | endpoint único de serviço é ponto de falha regional, não só de AZ | nenhuma ação aqui; é risco aceito na escala atual | baixa |
| Eficiência de performance | menos saltos de rede para tráfego interno à AWS | nenhum, na escala atual | nenhuma ação necessária | baixa |
| Otimização de custos | NAT removido; Gateway de graça; Interface medido contra o volume real | endpoint de interface pode ficar ocioso se o padrão de uso do serviço mudar | revisão trimestral de bytes processados por endpoint | alta |
| Sustentabilidade | menos hops de rede por requisição | nenhum adicional | nenhuma ação necessária | baixa |
O pilar que mais se move aqui não é o de custo
É tentador ler este laboratório como puramente FinOps, mas o pilar que mais avança é segurança: tráfego que nunca atravessa a fronteira pública reduz a superfície que uma auditoria de rede precisa explicar. A economia de custo é o efeito mais visível na fatura; a redução de superfície é o efeito mais relevante numa revisão de arquitetura.
Evolução em níveis: o que muda, e o que passa a doer
A terceira arquitetura não é um desenho novo: é a resposta a até onde levar a ideia de "tráfego que não precisa sair" — e cada nível troca um risco por outro, não só reduz custo.
NAT Gateway único, do L02, atendendo qualquer saída sem distinção.Gateway endpoint para S3, três Interface endpoints para o resto, NAT removido depois de medir.Um NAT (ou proxy) dedicado, com política de saída explícita, só para os destinos genuinamente fora da AWS que restarem.Endpoint centralizado numa conta de rede, compartilhado por Resource Access Manager entre várias VPCs e contas da organização (L45).Service Control Policy exigindo que toda VPC nova tenha endpoint para S3 e DynamoDB por padrão, e proibindo `0.0.0.0/0` em tabela de rotas privada sem justificativa registrada.Histórico de bytes processados por endpoint e por NAT, correlacionado a deploy e a feature, para prever qual serviço novo já nasce precisando de endpoint dedicado.A ordem não é negociável, e o motivo é concreto
Centralizar endpoints entre contas (nível 4) sem primeiro ter a decisão de QUAIS serviços merecem endpoint (nível 2) é compartilhar a pergunta errada em escala. É a mesma medição de Flow Logs deste laboratório, só que decidida uma vez para a organização inteira em vez de uma VPC — e ela precisa existir antes.
Onde IA entra, e onde não entra
Aqui, IA não agrega — e a razão é específica
A decisão deste laboratório (qual endpoint criar, se o NAT pode sair) é determinística: depende de bytes medidos, contra um catálogo fechado de dois tipos de endpoint. Um modelo não decide isso melhor que uma consulta de Flow Logs com limiar documentado — ele só adicionaria uma caixa preta onde já existe uma resposta exata. Onde IA realmente ajuda nesta vizinhança é detectar o padrão ANÔMALO de tráfego que uma regra fixa não prevê — por exemplo, um endpoint de repente processando volume muito acima do histórico, possível sinal de exfiltração via política aberta demais. Essa é a tarefa do GuardDuty, tratada no L48, e não algo para construir aqui com um modelo próprio.
Anti-padrões
| Anti-padrão | Por que alguém faz | Sintoma em produção | Forma correta |
|---|---|---|---|
| Criar Interface endpoint para o S3 | parece consistente usar o mesmo tipo de recurso para tudo, e a diferença entre os dois tipos não é óbvia pelo nome | cobrança de hora-AZ para um destino que tinha opção gratuita | Gateway endpoint sempre que o serviço suportar — hoje, só S3 e DynamoDB |
| Remover o NAT sem medir tráfego antes | a fatura já convenceu, e medir parece burocracia quando "obviamente" só sobrou tráfego migrado | apagão de um destino externo que ninguém tinha listado | duas semanas de Flow Logs, ou a métrica de bytes do NAT, antes de qualquer `destroy` |
| Endpoint de interface sem DNS privado | a criação padrão do console não marca a caixa por padrão, e o endpoint "parece" pronto assim que fica `available` | tudo funciona enquanto o NAT existe; quebra em silêncio quando ele sai | `private_dns_enabled = true` explícito, e prova 1 (dig) antes de remover o NAT |
| Política de endpoint no padrão (libera tudo) | o padrão já funciona, e escrever a política restrita exige saber o ARN exato do recurso, um passo a mais | alcance a bucket ou segredo fora do que a aplicação deveria tocar | política restrita ao ARN específico, no mesmo commit que cria o endpoint |
| Endpoint de interface numa AZ só, para economizar | metade da parte fixa parece economia óbvia, e "funciona" nos testes que rodam numa AZ só | a outra AZ perde acesso ao serviço se a primeira falhar, ou sofre latência cross-AZ | as duas AZs, sempre — é o mesmo requisito de disponibilidade que o L02 já declarou |
Quando algo não funciona
| Sintoma | Causa provável | Onde investigar | Correção |
|---|---|---|---|
| Aplicação não lê mais o segredo, sem NAT no ar | DNS privado não habilitado no endpoint | `dig` do hostname público de dentro da task | habilitar `private_dns_enabled` e recriar o registro DNS |
| DNS resolve para IP privado, mas a conexão falha | security group do endpoint sem regra de entrada do security group da task | tentativa de conexão TCP direta na porta resolvida | adicionar a regra de ingress correspondente |
| S3 responde em uma sub-rede e não na outra | Gateway endpoint associado a uma tabela de rotas só | comparar `route_table_ids` do endpoint com as tabelas privadas existentes | adicionar a tabela faltante em `route_table_ids` |
| Chamada ao S3 funciona, mas a um bucket específico dá acesso negado | política do endpoint restrita a outro ARN, ou IAM da task sem a permissão | comparar o ARN chamado com o `Resource` da política do endpoint E a policy IAM da task | as duas políticas — endpoint e IAM — têm de permitir; qualquer uma negando barra a chamada |
| Fatura de rede não caiu como esperado | endpoint de interface de baixo volume custando mais em hora do que o NAT custava em GB para aquele serviço | comparar bytes processados pelo endpoint com a hora-AZ acumulada no mês | reverter esse serviço específico para NAT, se ele voltar a existir, ou aceitar o custo fixo |
Limpeza: o que o destroy leva, e o que não leva
# Ordem importa: remover o Gateway endpoint antes da tabela de rotas que o referencia
# falha (dependencia); o Terraform resolve isso sozinho num destroy completo, mas nao
# numa remocao parcial manual.
terraform destroy \
-target=aws_vpc_endpoint.interface \
-target=aws_vpc_endpoint_policy.secrets \
-target=aws_security_group.endpoints
# So depois de confirmar (prova 4) que o NAT nao processa bytes:
terraform destroy -target=aws_nat_gateway.nat -target=aws_eip.nat
# Confirme que nao sobrou Elastic IP orfao — ele cobra sozinho, sem nenhum
# recurso visivel apontando para ele.
aws ec2 describe-addresses --query 'Addresses[?AssociationId==null]' --output table| Recurso | O `destroy` remove? | Cuidado |
|---|---|---|
| Gateway endpoint | sim, junto com a rota que ele injetou na tabela | nenhum — a rota some com o endpoint, automaticamente |
| Interface endpoint | sim, junto com a ENI | a ENI pode levar alguns minutos para desaparecer do console depois do comando retornar |
| Security group dos endpoints | sim, se nada mais o referenciar | falha se ainda houver endpoint usando — destrua os endpoints primeiro |
| NAT Gateway | sim | não some instantaneamente; o Elastic IP associado é um recurso separado |
| Elastic IP do NAT | só se declarado no mesmo Terraform e alvo do destroy | IP não associado a nada continua sendo cobrado até ser liberado explicitamente |
| Política de endpoint restrita | sim, junto com o endpoint | se você recriar o endpoint depois, a política volta ao padrão até ser reaplicada |
O Elastic IP é o recurso que mais sobrevive a uma limpeza incompleta
Ele não depende de nada e nada depende dele depois que o NAT some — é fácil esquecer porque ele não aparece como "quebrado" nem como "em uso": aparece só como uma linha pequena e recorrente na fatura, exatamente do jeito que o NAT inteiro aparecia antes deste laboratório.
Resumo
| Problema | Peça que resolve | Motivo |
|---|---|---|
| Tráfego para o S3 pagando NAT | Gateway endpoint | rota de prefixo, sem ENI, sem cobrança — o único mecanismo gratuito do laboratório |
| Tráfego para ECR, Secrets Manager e Logs pagando NAT | três Interface endpoints | ENI por sub-rede, com DNS privado fazendo o código não mudar |
| Código que não pode mudar | DNS privado habilitado | reescreve a resolução do hostname público para o IP da ENI, de forma transparente |
| Alcance indevido a recurso de outra conta | política de endpoint restrita ao ARN | a política padrão libera tudo; restringir é decisão explícita, não acidente |
| NAT sem função depois da migração | remoção medida, não assumida | Flow Logs por duas semanas provam ausência de tráfego externo antes do destroy |
O fluxo em 10 passos: medir o tráfego do NAT por Flow Logs → identificar que é 100% S3/ECR/Secrets Manager/Logs → criar o Gateway endpoint do S3, restrito por política → associá-lo às tabelas de rotas privadas → criar os três Interface endpoints, com DNS privado e security group próprio → provar a resolução de DNS com `dig` → provar conectividade com o NAT ainda no ar → confirmar bytes zerados no NAT → remover NAT e Elastic IP → confirmar a tabela de rotas sem 0.0.0.0/0.
O que a Cadência levou deste laboratório
Não foi só a queda na fatura — foi o hábito de medir antes de remover. O mesmo raciocínio (Flow Logs, hipótese declarada, prova antes do destroy) volta a valer no L45, quando a pergunta deixa de ser "este tráfego é da AWS" e passa a ser "este tráfego precisa mesmo sair para outra rede".
Perguntas frequentes
❓ Preciso de NAT Gateway para a task no Fargate falar com o S3?
❓ Gateway endpoint e Interface endpoint são a mesma coisa com nome diferente?
❓ O que acontece se eu esquecer de habilitar o DNS privado no endpoint de interface?
❓ Um endpoint de gateway para o S3 deixa meu tráfego privado por padrão?
❓ Vale a pena criar endpoint de interface para um serviço que a aplicação usa pouco?
❓ Remover o NAT Gateway quebra o acesso à internet de toda a aplicação?
❓ Preciso de um endpoint de interface por zona de disponibilidade?
❓ O Gateway endpoint do S3 usa security group?
Fixando
Uma equipe substitui o NAT Gateway por um Interface endpoint para o Secrets Manager, mas a aplicação — sem nenhuma mudança de código — continua tentando resolver o hostname público do serviço para um IP público, e falhando. O que provavelmente foi esquecido?
A Cadência mede o volume mensal de cada tipo de tráfego antes de decidir a arquitetura de rede. Qual das afirmações abaixo descreve corretamente quando manter o NAT Gateway, mesmo depois de criar os endpoints para S3, ECR, Secrets Manager e CloudWatch Logs?
Fechamento
Conhecimentos anteriores: sub-rede privada e tabela de rotas (L02), rolling update e ECR (L03), Secrets Manager (L04), upload direto ao S3 (L17). Conhecimento adquirido: a diferença mecânica entre Gateway e Interface endpoint, a leitura de DNS privado, e a disciplina de medir antes de remover infraestrutura que parece ociosa.
Próximo laboratório
O L45 estende a mesma pergunta — "esse tráfego precisa mesmo sair?" — para fora da AWS: VPN, Direct Connect e Transit Gateway, para quando existe um datacenter ou escritório do outro lado. O L99 volta ao PrivateLink numa escala maior: roteamento multi-região para IA, quando o modelo e o dado podem não estar na mesma região.
Documentação consultada em 07/ago/2026: AWS PrivateLink concepts, Gateway endpoints e Access AWS services through AWS PrivateLink, em docs.aws.amazon.com/vpc/latest/privatelink/. Data da última validação técnica: 07/ago/2026.
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…