Firewalls de host em servidores Linux são cada vez mais tratadas como código de aplicação: as regras ficam num repositório, as alterações passam por uma revisão e uma ferramenta distribui-as. Isso está certo – e, na transição, arma uma armadilha fácil de passar despercebida. No fim, fica um servidor que se comporta de forma totalmente normal e, mesmo assim, já não filtra nada.
Este artigo explica o mecanismo com o exemplo do nftables, o framework de filtragem de pacotes das distribuições Linux atuais, descreve uma sequência segura para a migração e acrescenta dois outros pontos de tropeço: regras derivadas de sockets abertos e portas de contentor que passam ao largo da firewall do host.
Como funciona o serviço da distribuição
Com o pacote nftables, o Debian fornece um serviço systemd nftables.service. O seu ficheiro de unit é curto e inequívoco: no arranque e no reload, carrega o ficheiro /etc/nftables.conf com nft -f. Na paragem, executa nft flush ruleset.
Soma-se a isso o ficheiro de configuração fornecido em conjunto, cuja primeira instrução é flush ruleset. A wiki do nftables descreve o que esse comando faz: apaga o conjunto de regras completo – «flush (erase, delete, wipe) the complete ruleset» (esvaziar – apagar, eliminar, limpar – o conjunto de regras completo). Não se trata apenas das tabelas que esse serviço criou, mas de tudo o que está carregado no kernel.
Para um servidor em que apenas esse serviço gere regras, este é um design sensato: o conjunto de regras é substituído por completo a cada carregamento, e não sobram resquícios de estados anteriores.
A armadilha na troca de mecanismo
O problema surge assim que entra um segundo mecanismo. Um desenrolar típico: as regras passam a vir de um repositório e a ser carregadas por uma gestão de configuração ou por um serviço próprio, numa tabela própria. O novo conjunto de regras é carregado, verificado e aprovado. O serviço antigo continua lá, porque afinal não atrapalha.
Algum tempo depois, acontece uma de três coisas:
- Alguém para o serviço antigo, por exemplo durante uma limpeza. A paragem esvazia o conjunto de regras inteiro – incluindo a nova tabela. O host fica, a partir daí, sem filtragem.
- Alguém o reinicia ou o recarrega. O ficheiro antigo é aplicado, e o seu
flush rulesetremove tudo o que não está nele. O host volta a correr com o estado que tinha sido substituído. - Alguém aplica o ficheiro antigo manualmente para «testar algo rapidamente» – com o mesmo resultado.
Em nenhum dos casos aparece uma mensagem de erro. Os serviços continuam acessíveis, as aplicações funcionam, a monitorização continua verde. É exatamente isso que torna a armadilha perigosa: os testes habituais após uma alteração verificam se algo funciona – não se algo é bloqueado.
A sequência segura
A solução não é uma nova técnica, mas uma sequência:
- Desativar ou mascarar o serviço antigo, sem o parar. A página de manual do systemctl é inequívoca aqui:
disablenão para a unit; só a opção--nowo faz.maskvai mais longe e impossibilita qualquer arranque, incluindo o manual. Umstopseria exatamente o comando que esvazia o conjunto de regras. - Carregar o novo conjunto de regras – numa tabela própria, a partir do repositório, através do mecanismo que o passará a gerir.
- Ler o que está de facto carregado.
nft list tablesmostra que tabelas existem;nft list rulesetmostra o estado completo. Nesta fase, a tabela antiga e a nova devem estar lado a lado. As duas atuam ao mesmo tempo – mantenha esta fase curta. - Comprovar a filtragem a partir de fora – mais sobre isso a seguir.
- Só então remover a tabela antiga de forma direcionada, com
nft delete table, e não parando o serviço antigo. O ficheiro de configuração antigo é arquivado ou alterado de modo que uma aplicação acidental já não esvazie nada. - Após o próximo reinício, ler novamente se o novo conjunto de regras está carregado e se o antigo não voltou.
Um detalhe merece atenção: desativar e mascarar impedem um novo arranque, mas não terminam o estado em execução. Como a unit está definida como serviço de execução única com RemainAfterExit=yes, para o systemd continua a constar como ativa até ao próximo reinício – e o seu comando de paragem continua registado. Documente isso como risco conhecido.
O teste negativo a partir de fora
Após cada alteração de firewall, verifica-se se os serviços permitidos estão acessíveis. Isso comprova que nada está avariado. Que há filtragem, isso não comprova – um host sem nenhuma regra passa nesse teste da mesma forma.
Por isso, toda a alteração exige um teste negativo: uma tentativa de ligação a partir de uma origem fora do host, que tem de ser bloqueada, para uma porta que tem de estar fechada. Só quando essa tentativa falha está o efeito comprovado. «Fora» deve ser entendido à letra: ligações que um host estabelece consigo próprio passam pela interface de loopback, que os conjuntos de regras costumam permitir de forma geral.
Repita o teste regularmente, não só em alterações: a armadilha descrita pode fechar-se semanas depois.
Regras a partir do repositório, não da shell
Comandos ad hoc na consola são o adversário natural de qualquer gestão de regras como código. Uma regra que existe apenas no kernel em execução desaparece no próximo carregamento a partir do repositório – ou sobrevive onde ninguém a espera, porque alguém exporta o estado em execução para um ficheiro. As duas coisas tornam o conjunto de regras imprevisível. A regra é simples: o que não está no repositório revisto não pertence ao host. Alterações de emergência são incorporadas depois, e uma comparação regular entre o repositório e nft list ruleset torna os desvios visíveis.
Nem todo o socket aberto precisa de uma regra
Ao montar um novo conjunto de regras, é tentador percorrer a lista de sockets abertos de um host e criar uma permissão para cada um. Isso leva a aberturas desnecessárias. Um exemplo é um socket UDP que um serviço de log usa apenas para envio, por exemplo ao encaminhar mensagens de syslog para um servidor central. Aparece na lista de sockets, mas não precisa de regra de entrada.
Derive as permissões da finalidade: que ligações deve o host aceitar e de quem? A lista de sockets é uma ferramenta de controlo, não o modelo.
Portas de contentor passam ao largo da INPUT
O terceiro ponto de tropeço diz respeito a hosts com Docker. Segundo a documentação do Docker, as portas publicadas são, por predefinição, associadas a todos os endereços do host; publicar seria «insecure by default» (inseguro por predefinição). Os pacotes passam por um redirecionamento de NAT de destino e, na cadeia FORWARD, são reencaminhados para cadeias próprias do Docker. Para o UFW, a documentação formula a consequência expressamente: o Docker redireciona o tráfego de contentores na tabela nat antes que este chegue às cadeias INPUT e OUTPUT que o UFW utiliza. Uma regra INPUT mantida com cuidado, portanto, não vê uma porta de contentor publicada.
Se um serviço no contentor deve ser acessível apenas localmente, associe-o expressamente a 127.0.0.1, por exemplo com -p 127.0.0.1:8080:80. Aí, segundo a documentação, apenas o próprio host lhe pode aceder – com uma ressalva: antes do Docker 28.0.0, hosts no mesmo segmento de camada 2 também podiam alcançar portas publicadas em localhost. Para regras de filtragem que também devem atuar antes dos contentores, vale: com o backend iptables predefinido, o Docker prevê para isso a cadeia DOCKER-USER; com o backend nftables experimental, esta deixa de existir. Além disso, portas de contentor publicadas fazem parte de todo o teste negativo.
Como a sector7 apoia
Fazemos o hardening de sistemas operativos e serviços padrão e construímos consigo conjuntos de regras limpos e rastreáveis – mais em Cibersegurança. Análises de vulnerabilidades recorrentes e automatizadas verificam externamente a sua superfície de ataque e internamente sistemas e serviços; mostram quando uma porta está aberta sem que o devesse estar. No âmbito dos nossos Managed Network Services, assumimos também a gestão de mudanças.
Fontes
- nftables.service (fonte do pacote Debian) – Debian pkg-netfilter-team, consultado em 30 de setembro de 2026
- nftables.conf (fonte do pacote Debian) – Debian pkg-netfilter-team, consultado em 30 de setembro de 2026
- Operations at ruleset level – wiki do nftables, consultado em 30 de setembro de 2026
- Configuring tables – wiki do nftables, consultado em 30 de setembro de 2026
- systemctl(1), Debian Bookworm – Debian, consultado em 30 de setembro de 2026
- Packet filtering and firewalls – Docker, consultado em 30 de setembro de 2026
- Port publishing and mapping – Docker, consultado em 30 de setembro de 2026
- Docker with iptables – Docker, consultado em 30 de setembro de 2026
- Docker with nftables – Docker, consultado em 1 de outubro de 2026