Imagine um host Linux que termina uma VPN e também executa um contêiner numa rede macvlan. A LAN é 192.168.60.0/24, o contêiner tem 192.168.60.210 e os clientes VPN chegam de 10.95.0.0/24. O cliente alcança o serviço, a resposta nunca volta e toda regra de firewall no host parece correta. Duas restrições separadas produzem esse sintoma, e corrigir uma deixa a outra no lugar.

Duas restrições, um sintoma

A primeira restrição é o isolamento: o driver macvlan do Docker não permite que um contêiner fale com o próprio host pela interface pai. O tráfego entre a pilha do host e o contêiner não tem caminho, não importa como as rotas no host estejam escritas.

A segunda restrição é o caminho de volta. O gateway padrão do contêiner costuma ser o roteador da LAN, então uma resposta endereçada a um cliente VPN sai por esse roteador. Se o roteador não tiver rota de volta ao pool VPN, a resposta é descartada em algum ponto do meio.

As duas falhas parecem idênticas do ponto de vista do cliente: uma requisição que chega e uma resposta que nunca chega. Elas exigem reparos diferentes, e uma regra masquerade ampla pode esconder qual das duas continua quebrada. Por isso o primeiro teste é uma captura no lado do contêiner e não mais uma mudança no firewall. Se a requisição nunca aparece ali, é a restrição de isolamento que está em jogo.

Construa o shim do host, de forma estreita

Uma segunda interface macvlan no host, ligada ao mesmo pai em modo bridge, dá à pilha do host uma identidade própria naquele segmento da LAN. Reserve para ela um endereço fora do pool DHCP e fora da faixa do contêiner, e encaminhe apenas o contêiner por ela.

ip link add macvlan-vpn link eth0 type macvlan mode bridge
ip address add 192.168.60.250/32 dev macvlan-vpn
ip link set macvlan-vpn up
ip route add 192.168.60.210/32 dev macvlan-vpn src 192.168.60.250

O primeiro comando cria a interface em modo bridge, que é o padrão documentado para este driver e o modo que você quer para o tráfego entre host e contêiner. O segundo atribui um /32 para que o endereço não colida com o prefixo da LAN, e o quarto envia apenas o endereço do contêiner pelo shim.

Não redirecione toda a LAN pela interface nova. A rota conectada comum fica como está, e a rota do host é deliberadamente estreita para que um contêiner ganhe um caminho sem que o resto do segmento mude de comportamento. Uma rota padrão apontando para o shim seria outro desenho com outras consequências. Mantenha-a específica e o raio de impacto continua pequeno.

Esses comandos mudam a configuração de rede num host em funcionamento. Num appliance ou numa plataforma gerenciada, use o mecanismo de configuração suportado por essa plataforma, porque uma mudança interativa no shell root pode não sobreviver a uma atualização.

Decida como a origem é preservada

Com o shim no lugar, o contêiner consegue alcançar o host, e a pergunta passa a ser qual endereço de origem a resposta carrega. Preservar a origem VPN original é o modelo mais limpo: o contêiner vê o endereço real do cliente, e os logs e as regras de acesso do serviço podem usá-lo.

Para isso funcionar, a configuração de rede do contêiner precisa enviar, para este caminho, o tráfego de 10.95.0.0/24 para 192.168.60.250 como seu gateway. Isso é um ajuste de rota ou de gateway suportado dentro da própria configuração do contêiner, não um truque do lado do host. Confirme-o de dentro do contêiner em vez de supor que o ajuste entrou em vigor. Um gateway padrão que ainda aponta para o roteador da LAN continuará enviando respostas para o mesmo buraco.

Se o desenho aprovado, em vez disso, oculta as origens VPN, limite a tradução de forma estreita: o pool VPN real, o shim como interface de saída e o contêiner e o serviço específicos.

iptables -t nat -A POSTROUTING -s 10.95.0.0/24 -o macvlan-vpn -j SNAT --to-source 192.168.60.250

Faça o shim coincidir como interface de saída, não o túnel. Uma regra que nomeia o túnel como interface de saída não vai coincidir com um pacote indo em direção ao contêiner, e esse é o erro que esse tipo de montagem costuma conter. Mantenha a regra tão estreita quanto a frase acima e revise-a quando o pool mudar.

Verifique do cliente, não do host

Uma requisição do próprio host, vinculada ao endereço do shim, prova que o shim consegue alcançar o contêiner. Não prova que o contêiner consegue devolver tráfego para uma origem preservada 10.95.0.x, porque o endereço de origem nesse teste é o do próprio shim.

curl -sS --interface 192.168.60.250 -o /dev/null -w '%{http_code}\n' http://192.168.60.210:8080/health
sudo tcpdump -ni macvlan-vpn host 192.168.60.210

O primeiro comando testa o trecho do host ao contêiner, e o segundo mostra o que realmente cruza o shim enquanto um cliente VPN real faz a requisição. Olhe o endereço de origem na entrada e se aparece uma resposta com o mesmo fluxo.

O encaminhamento precisa estar habilitado no host, e o caminho de encaminhamento precisa de uma permissão para o pool VPN rumo ao shim na porta do serviço, além das respostas estabelecidas. Uma regra INPUT no host não autoriza o tráfego encaminhado, e essa é uma causa comum de o pacote ser descartado depois que o roteamento parece correto.

Execute a aplicação real com credenciais reais e depois verifique se um segundo serviço não relacionado no mesmo contêiner continua recusando você. Se a única forma de fazer isso funcionar era abrir todas as regras de encaminhamento, o desenho não está terminado. Anote também qual endereço de origem o serviço registrou, porque é esse que as próprias regras de acesso dele vão usar de agora em diante.

Artigos relacionados