Quando você cria uma aplicação segura, o normal é bloquear qualquer conexão para fora da Virtual Private Cloud (VPC). Mas, em algum momento, é preciso abrir uma brecha — por exemplo, quando sua aplicação precisa acessar uma API de terceiros.

Gateway to Domain, no estilo Lovecraft. Crédito: StableDiffusion
O caminho mais comum é liberar egress apenas para os endereços IP relevantes, configurando isso no Firewall do Google Cloud Platform ou nas Network ACLs da AWS. Só que endereços IP mudam com o tempo, enquanto o Fully Qualified Domain Name (FQDN), como api.example.com, oferece um endpoint estável e de conhecimento público. Por isso, a maioria das aplicações é configurada para acessar um FQDN, e não um endereço IP.

Neste artigo, vou mostrar formas de liberar egress apenas para um FQDN específico, com as vantagens e desvantagens de cada abordagem.
A ideia é encontrar opções baratas, fáceis de manter, robustas e simples.
Também vamos avaliar opções com o diferencial de reconhecer o Kubernetes: por exemplo, se sua aplicação roda em Kubernetes, você pode querer liberar egress a partir de um namespace específico, e não dos demais.
Outro ponto é a granularidade no nível dos domínios, já que um único endereço IP pode hospedar vários domínios, como acontece no virtual hosting baseado em nome. A maioria das soluções aqui não trata desse caso — se você libera o acesso a um domínio com determinado IP, elas vão liberar egress para todos os domínios por trás daquele endereço. Vamos apresentar algumas soluções que dão conta disso.
As opções analisadas aqui são:
- Squid, como exemplo de proxy autogerenciado
- AWS Network Firewall, com deep packet inspection, que permite controle no nível do domínio, mesmo com virtual hosting.
- Um novo recurso no Google Firewall, que entrega controle por FQDN com a praticidade de um serviço serverless
- O novo Google Secure Web Gateway, que adiciona controle granular no nível do domínio e até da URL.
- Soluções com reconhecimento de Kubernetes: Cilium e Istio.
(Uma observação sobre as camadas OSI: como nomes de domínio e DNS estão na "camada de aplicação" do modelo de rede OSI, a Camada 7, o controle de egress por FQDN às vezes é chamado de "controle de egress da Camada 7". Já a Camada 3 é onde os endereços IP são definidos e controlados em firewalls tradicionais ou Network ACLs.)
Implementando por conta própria
Primeiro, vamos pensar em como dá para implementar isso sozinho. Não que eu recomende, mas o exercício ajuda a entender o que essas soluções fazem por baixo dos panos.
Mesmo que a aplicação seja configurada com o FQDN da API de terceiros, os nomes de domínio só importam antes da tentativa de conexão, no momento em que o cliente busca o endereço IP a partir do nome de domínio. Daí em diante, o tráfego de rede passa a usar endereços IP — e é isso que sua solução precisa bloquear.
Vale lembrar também que um único FQDN pode corresponder a vários endereços IP. Isso não é um problema, já que uma busca DNS comum retorna todos eles, e você pode liberar acesso a uma lista de endereços IP.
Você tem um Firewall ou uma Network ACL que bloqueia todo o tráfego, exceto para os endereços IP relevantes.
Você escreve e implanta uma aplicação que consulta o DNS periodicamente para descobrir o endereço IP atual do FQDN da API, api.example.com. (Uma boa escolha para rodar isso a baixo custo é o GCP Cloud Functions ou o AWS Lambda com gatilho periódico.) Nos raros casos em que o endereço IP mudou, sua aplicação atualiza o Firewall ou a Network ACL.
Reverse web proxies autogerenciados
Uma solução "clássica" para controle de egress por FQDN é um reverse web proxy, e o Squid é o mais conhecido entre os de código aberto. Você usa o serviço de roteamento da sua nuvem para direcionar todo o tráfego de saída por uma VM que executa o proxy Squid; ele então confere se o endereço IP corresponde ao nome de domínio — conforme definido em uma whitelist ACL — e encaminha o tráfego se houver correspondência.
O Squid está disponível no AWS Marketplace; veja esta discussão de arquitetura. Também está disponível no GCP Marketplace; veja esta configuração de rede. Veja também esta discussão sobre controle de egress por FQDN no Squid e em outros proxies, como DiscrimiNAT e Aviatrix.
Proxies como o Squid rodando em uma VM trazem custo de manutenção — por exemplo, atualizar os sistemas operacionais das VMs e lidar com falhas. Como todo o fluxo de tráfego de rede passa por uma única VM (a menos que você tenha o trabalho extra de configurar uma implantação com balanceamento de carga), a carga pode ser pesada, o que compromete a robustez e pode exigir uma VM maior rodando 24x7, mesmo quando ela não é totalmente necessária.
AWS Network Firewall
O AWS Network Firewall faz deep packet inspection e, com isso, ganha mais poder de filtragem. Ou seja, ele não é estritamente comparável ao Google Firewall, que se aproxima mais das Network ACLs da AWS.
O AWS Network Firewall suporta controle de egress por FQDN por meio de stateful domain list rule groups. Usando o Server Name Indicator (SNI) enviado durante a negociação de uma conexão TCP para tráfego HTTPS, ele consegue diferenciar domínios em cenários de virtual hosting.
O Network Firewall pode ser integrado ao Route 53 DNS Firewall, que bloqueia tentativas de resolução DNS — assim, por exemplo, uma consulta DNS para api.example.com a partir de uma aplicação dentro da VPC não resolve para um endereço IP. Mas o DNS Firewall, na prática, não impede o acesso a esse endereço IP; quem faz isso é o Network Firewall.
O Network Firewall é uma boa escolha, mas pode sair caro: foi pensado para ambientes corporativos complexos, com várias redes. (Veja meu artigo no Blog da DoiT comparando os casos de uso dos diversos serviços de Firewall na AWS.)
Google Firewall e Web Gateway
É mais prático usar uma solução totalmente gerenciada pelo provedor de nuvem do que cuidar da VM você mesmo. E o Google está justamente lançando algumas soluções nessa direção.
O Google Firewall tem um novo recurso FQDN Objects, hoje em Preview limitado. Ele usa o Cloud DNS a cada 30 segundos para consultar o endereço IP atual do serviço externo.
Outro serviço em Preview limitado, o Secure Web Gateway (renomeado para Secure Web Proxy), também permite controle no nível do domínio. Para isso, você concede a ele acesso aos seus certificados SSL no GCP Certificate Manager, para que possa descriptografar e criptografar seu tráfego HTTPS. Esse acesso profundo dá a ele o poder de controlar egress no nível do domínio, mesmo em cenários de virtual hosting. E como ele enxerga toda a requisição HTTP, permite até controle no nível da URL.
Cilium
As soluções acima funcionam no nível da VPC. Mas, se sua aplicação roda em Kubernetes, talvez você queira que o controle de egress trabalhe com conceitos do próprio Kubernetes. Para isso, dá para usar a CiliumNetworkPolicy. É uma Custom Resource Definition (CRD) que executa a lógica de resolver nomes de domínio para endereços IP e, depois, bloqueia ou libera o tráfego na camada de rede do Cilium, baseada em eBPF. (Veja dois posts no blog da DoiT.) A CRD reconhece o Kubernetes, então você consegue distinguir pods por namespace: alguns têm permissão de acesso à API externa, outros não. Outra CRD, a CiliumClusterwideNetworkPolicy, faz o mesmo, mas sua configuração se aplica entre namespaces, valendo para o cluster inteiro.
Essa solução adiciona certa complexidade ao cluster, por causa da camada de rede extra do Cilium. Em breve, conforme indicado na documentação do Cilium, "toda a funcionalidade será mesclada ao formato de recurso padrão e essa CRD não será mais necessária." Ainda não há uma especificação padrão disponível, mas o Kubernetes Networking Special Interest Group já está trabalhando nisso.
Istio
A solução mais completa em recursos é o service mesh Istio. Ele controla todo o tráfego, permitindo bloquear todo o egress, exceto o que estiver definido em uma ServiceEntry. Quando você especifica resolution: DNS, pede ao Istio para não confiar no endereço IP ao qual o cliente (um pod) está se conectando, e sim resolver o nome de domínio periodicamente via DNS. O serviço Istio pode ser exposto apenas aos namespaces que você escolher. O Istio oferece o maior nível de controle, mas traz mais complexidade do que o Cilium, com todo o poder e a funcionalidade de uma camada de service mesh.
E aí, o que fazer?
Você tem um leque de opções: o Squid, já testado em campo (ou outro reverse web proxy); os novos serviços gerenciados, Google Firewall FQDN Objects e AWS Network Firewall; o Secure Web Gateway, que faz proxy HTTP; e, ainda, o Cilium e o Istio com reconhecimento de Kubernetes.
Se você quer uma solução estável e gerenciada, minha recomendação é apostar no novo Google Firewall (assim que amadurecer) e no AWS Network Firewall (se o preço couber no seu orçamento). Se precisar de controle no nível de namespaces do Kubernetes, o caminho mais simples é uma CRD do Cilium; quando o padrão nativo do Kubernetes for lançado, vá nele.
Adendo
Agosto de 2023: meu colega
publicou recentemente artigos aprofundados sobre vários desses temas, contemplando lançamentos do Google que estavam em alpha quando escrevi este artigo e trazendo mais detalhes técnicos.