Uma firewall que só admite a porta VPN não é uma regra. São três decisões separadas que, por acaso, envolvem o mesmo número de porta: a cadeia de entrada decide o que pode chegar a um processo local, a cadeia de encaminhamento decide o que pode atravessar o anfitrião em nome dos clientes do túnel, e a tabela NAT reescreve o endereço de origem à saída. Erre uma delas e o resultado raramente é uma queda limpa. Fica com um anfitrião que aceita clientes mas não carrega nada, ou um anfitrião que parece fechado até alguém ler a ordem das cadeias.

A única porta que não pode ser fechada

O ouvinte de VPN tem de aceitar ligações de endereços que não consegue prever, pelo que é um serviço público por definição. É a única exceção em torno da qual o projeto é construído: uma porta UDP para OpenVPN, uma porta UDP para WireGuard, uma porta TCP para uma VPN SSL. Tudo o resto pertence atrás do túnel, o que significa que os serviços de aplicação se devem ligar ao endereço do túnel ou ao loopback, e não a todas as interfaces.

Ligar, porém, não é aplicar. Um processo ligado a 0.0.0.0 só é alcançável se uma regra o admitir, e a política predefinida é o recurso para o tráfego que nenhuma regra apanhou, não a regra que governa a porta. Uma aceitação colocada acima da sua rejeição continua a ser uma aceitação, e retirar um serviço do endereço público é uma melhoria independente, não um substituto da cadeia.

Entrada, encaminhamento e NAT respondem a perguntas diferentes

O tráfego de entrada destina-se ao próprio anfitrião, por isso é aí que vivem o ouvinte de VPN e o caminho administrativo. O tráfego de encaminhamento atravessa o anfitrião, e os clientes do túnel precisam dele além de net.ipv4.ip_forward=1. A configuração clássica meio avariada permite o fluxo de saída e esquece o sentido de retorno, pelo que o cliente conclui o handshake e depois nada carrega; uma regra conntrack para tráfego estabelecido e relacionado cobre esse sentido.

NAT é a terceira pergunta. Sem reescrita em postrouting, os pacotes encaminhados saem com a origem privada do túnel e são descartados mais acima, porque nenhuma rede para lá do anfitrião sabe encaminhar o conjunto de volta. O prefixo de origem nessa regra tem de corresponder ao conjunto da VPN, não ao endereço do próprio anfitrião, e o mesmo vale para a regra de encaminhamento que nomeia a sub-rede dos clientes.

IPv6 é uma segunda política, não um pensamento posterior. Um anfitrião com uma cadeia IPv4 estrita e uma política aberta em ip6tables não fechou nada; os serviços continuam alcançáveis pela outra família. Ou reflete o conjunto de regras com ip6tables, ou desativa o IPv6 deliberadamente na interface pública, e anota qual escolheu.

Uma base legível numa só passagem

Comece pela rejeição e só depois acrescente o que o anfitrião precisa. Primeiro loopback e respostas, depois o caminho administrativo, depois o ouvinte do túnel, depois a política de encaminhamento para os clientes:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -m conntrack --ctstate NEW -j ACCEPT
sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Os nomes das interfaces, a porta e o conjunto são marcadores de posição; leia-os do servidor em vez de os copiar. Guardar o resultado é tão importante como escrevê-lo, porque um conjunto de regras que só vive na memória desaparece no reinício seguinte e reabre o anfitrião em silêncio. Torne-o persistente com o mecanismo da distribuição e guarde uma cópia fora da máquina para o dia em que a máquina não arrancar.

Fechar a última porta sem perder o anfitrião

Há uma armadilha no projeto. Se o SSH só existir através do túnel, um serviço de VPN em falha leva o SSH consigo, e o único caminho de volta pode ser uma consola que nunca abriu. Antes de fechar a última porta pública, confirme que essa consola existe e que a consegue mesmo usar, ou mantenha um caminho administrativo estreito que não dependa do túnel: SSH a partir de um endereço fixo, só chaves, autenticação por palavra-passe desligada.

Aplique a alteração a partir de uma sessão já estabelecida, não através da ligação que está prestes a filtrar. Agende um retrocesso para que um erro expire em vez de se tornar permanente, por exemplo uma tarefa systemd-run --on-active=10min que restaura o conjunto de regras anterior, e mantenha uma segunda sessão SSH aberta enquanto testa a primeira. Depois verifique se a tarefa de retrocesso dispara mesmo, porque uma recuperação não testada é o mesmo que nenhuma recuperação.

Verifique o caminho, não o script

Leia as regras carregadas, não o ficheiro que as devia carregar. A partir de um anfitrião externo autorizado, confirme que só as portas previstas respondem; de dentro do túnel, confirme que os serviços que queria publicar são alcançáveis. Uma política de rejeição predefinida que também bloqueia o tráfego do túnel parece idêntica a um bloqueio a funcionar até alguém tentar usá-lo.

iptables -S
iptables -t nat -S
ss -lntup
ip -4 addr show

Anote a porta permitida, o conjunto de clientes, a interface do túnel, a origem administrativa e o procedimento de consola ao lado da configuração. A alteração seguinte no conjunto ou no nome da interface tem de ser refletida tanto no filtro como na regra NAT, senão o anfitrião volta a um estado meio aberto sem que ninguém note.

Um hábito vale mais do que o conjunto de regras: depois de cada alteração, prove o caminho de encaminhamento com um pedido de cliente e o caminho de recuperação com uma segunda sessão. Um bloqueio que não usou é uma hipótese.

Artigos relacionados