Preserve ou aplique SNAT aos IPs dos clientes VPN na borda da nuvem
Preservar a origem mantém a identidade do cliente em cada registro, o SNAT mantém a tabela de rotas pequena. Três condições dizem qual a aplicação precisa.
Manter o endereço do cliente VPN até a aplicação faz com que cada linha de registro e cada entrada da lista de permissões signifiquem a mesma coisa. Reescrevê-lo na borda da nuvem torna a tabela de rotas mais simples e os registros menos úteis. Nenhuma das escolhas está errada por si só, e o argumento que a decide raramente é sobre desempenho. Três condições a resolvem: se a aplicação precisa saber qual pessoa se conectou, se a malha da nuvem aceitará a origem que você pretende enviar e quem aceitará assumir a rota de retorno depois.
Três condições a decidem
Comece pelo requisito da aplicação, não pelo diagrama de rede. Se a autorização ou a auditoria dependem do endereço individual do cliente, preservá-lo é um requisito funcional e traduzi-lo é uma regressão. Se a aplicação só precisa saber que o tráfego chegou pelo caminho de acesso remoto, um endereço traduzido é suficiente e muito mais barato de operar.
A segunda condição é mecânica. Uma rede virtual não confia automaticamente num pacote que afirma um endereço que não foi atribuído à interface emissora. A maioria das malhas de nuvem impõe isso, de formas e com nomes diferentes, e um projeto que o ignora parecerá correto no diagrama e descartará em silêncio em produção.
A terceira é organizacional. Preservar as origens significa que a tabela de rotas da sub-rede da aplicação precisa apontar de volta para o gateway para o prefixo do cliente, e cada equipe que adicionar uma sub-rede depois precisa manter essa rota consistente. É um custo pequeno uma vez e recorrente em dezenas de contas. Decida quem o paga antes de prometer o comportamento.
Uma rota não é permissão para falsificar
Adicionar uma rota de retorno diz à sua sub-rede para onde as respostas devem ir. Não diz à malha que a instância que encaminha esses pacotes tem permissão para emiti-los com uma origem estrangeira. Na AWS o controle relevante é a verificação de origem e destino, e ela é visível por instância:
aws ec2 describe-instances --instance-ids i-0a1b2c3d4e5f60718 \
--query "Reservations[].Instances[].SourceDestCheck"
aws ec2 modify-instance-attribute --instance-id i-0a1b2c3d4e5f60718 \
--no-source-dest-check
Desative-a apenas para a instância cujo trabalho documentado é o encaminhamento, e para nada mais. Cada VM de aplicação que mantém a verificação ativa é uma máquina menos que pode ser usada para emitir tráfego com uma origem emprestada. Se a sua plataforma não for AWS, procure a configuração equivalente de anti-falsificação ou de endereços permitidos em vez de supor que o comportamento se transfere.
Uma captura de pacotes rápida resolve a questão mais rápido do que ler o console. Se as respostas saem e o cliente nunca as vê, é a malha que descarta a origem falsificada, e não a aplicação que falha.
O que a tradução compra e quanto custa
Reescrever a origem no gateway elimina o problema do caminho de volta. A aplicação vê um endereço que já sabe como alcançar, e o prefixo do cliente nunca precisa aparecer numa tabela de rotas da nuvem. No Linux a regra é uma linha, e vale a pena escrever a versão mais estreita que você conseguir:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 172.20.8.0/24 -o ens5 -j SNAT --to-source 10.40.3.10
Observe o que a aplicação agora registra: 10.40.3.10 para cada usuário, em cada conexão, para sempre. Qualquer lista de endereços permitidos construída sobre esse valor agora concede acesso a toda a população de acesso remoto, e qualquer revisão de incidente precisa voltar ao gateway para responder quem era.
A solução não é abandonar a tradução, é parar de fingir que o endereço é uma identidade. Carregue a identidade do cliente num campo autenticado, registre-a no gateway junto com a tupla traduzida e deixe a aplicação juntar por ela. Sem a chave de junção, a tradução converte um problema de rede num problema forense permanente.
O relé é uma interface diferente
Um proxy reverso à frente da aplicação contorna por completo a questão do caminho roteado. O proxy abre a própria conexão de backend, então o prefixo do cliente nunca precisa ser roteável dentro da rede virtual, e a aplicação pode receber a identidade num cabeçalho que o proxy define.
Esse cabeçalho só é confiável quando o backend o aceita do proxy e de nada mais. Em termos de nginx isso significa nomear explicitamente o par confiável em vez de acreditar em qualquer coisa que chegue:
set_real_ip_from 10.40.3.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Qualquer cliente que consiga alcançar o backend diretamente pode falsificar o mesmo cabeçalho, portanto o backend precisa ser inalcançável exceto pelo proxy. Isso é um fato de firewall, não uma opinião de configuração, e é a suposição que as pessoas pulam ao copiar o trecho.
O relé também muda o que você compra. Você ganha uma identidade em nível de aplicação e um lugar natural para registrá-la; abre mão da generalidade, porque cada novo protocolo precisa do seu próprio suporte de proxy. Para serviços HTTP essa troca costuma ser boa, e para qualquer coisa que não seja HTTP normalmente não está disponível de forma alguma.
Anote o que cada fronteira vê
Escolha o que escolher, a revisão de projeto deve terminar com uma tabela que nomeie o endereço de origem e a identidade demonstrável em cada salto. Sem ela, o primeiro incidente produz três equipes que descrevem cada uma um cliente diferente.
| Boundary | Source the next hop sees | What is actually proven |
|---|---|---|
| Client to gateway | 172.20.8.14 | A certificate or credential was presented |
| Gateway to app subnet, preserved | 172.20.8.14 | The same session, if the return route exists |
| Gateway to app subnet, translated | 10.40.3.10 | Only that traffic came through the gateway |
| Proxy to backend | 10.40.3.10 plus a header | The proxy asserted an identity it authenticated |
Depois escolha. Preserve quando a autorização da aplicação depender de fato do endereço do cliente e você puder assumir a rota. Traduza quando não for o caso e você puder carregar a identidade fora de banda, e use as orientações da AWS para instâncias de encaminhamento para as configurações de encaminhamento específicas da plataforma. Recorra a um relé quando o serviço falar HTTP e você quiser que a identidade deixe de ser um endereço.