Configurando um firewall robusto com nftables no Linux

1. Fundamentos do nftables e substituição do iptables

O nftables representa a evolução do firewall no ecossistema Linux, substituindo o antigo sistema iptables/ip6tables/ebtables/arptables. Diferentemente do iptables, que opera com múltiplos módulos no userspace e uma arquitetura fragmentada no kernel, o nftables unifica o processamento de pacotes em uma única infraestrutura. Sua arquitetura é baseada em um interpretador de bytecode no kernel (nft), combinado com expressões genéricas que eliminam a necessidade de módulos específicos para cada tipo de regra.

Os conceitos fundamentais do nftables são: tabelas (containers lógicos), chains (listas ordenadas de regras) e regras (combinações de expressões e ações). O suporte a múltiplas famílias de endereços — ip (IPv4), ip6 (IPv6), inet (IPv4+IPv6), arp e bridge — permite gerenciar todo o tráfego de rede com uma sintaxe unificada.

Para instalar e verificar a versão:

# Debian/Ubuntu
sudo apt install nftables

# CentOS/RHEL/Fedora
sudo dnf install nftables

# Verificar versão
nft --version

2. Estrutura de tabelas e chains no nftables

A criação de tabelas define o escopo do firewall. Cada tabela pertence a uma família de endereços e contém chains que se conectam a hooks específicos do kernel:

# Criar tabela inet (IPv4+IPv6)
nft add table inet meu_firewall

# Criar chain filter para tráfego de entrada
nft add chain inet meu_firewall input { type filter hook input priority 0 \; policy drop \; }

# Criar chain para encaminhamento
nft add chain inet meu_firewall forward { type filter hook forward priority 0 \; policy drop \; }

# Criar chain para saída
nft add chain inet meu_firewall output { type filter hook output priority 0 \; policy accept \; }

Os tipos de chains disponíveis são: filter (filtragem padrão), nat (tradução de endereços) e route (alteração de roteamento). Os hooks definem em qual ponto do processamento de pacotes a chain será executada: prerouting (antes da decisão de roteamento), input (pacotes destinados ao host local), forward (pacotes roteados), output (pacotes originados localmente) e postrouting (após a decisão de roteamento). A prioridade (0 por padrão) determina a ordem de execução entre chains no mesmo hook.

3. Sintaxe básica de regras e expressões

A sintaxe do nftables é mais legível que o iptables, usando expressões encadeadas com operadores lógicos:

# Regra básica: bloquear SSH de um IP específico
nft add rule inet meu_firewall input ip saddr 192.168.1.100 tcp dport 22 drop

# Aceitar tráfego HTTP/HTTPS
nft add rule inet meu_firewall input tcp dport { 80, 443 } accept

# Bloquear ICMP de um intervalo de IPs
nft add rule inet meu_firewall input ip saddr 10.0.0.0/8 icmp type echo-request drop

# Usar expressões meta para interface
nft add rule inet meu_firewall input meta iifname "eth0" tcp dport 22 accept

Os veredictos disponíveis são: accept (permitir), drop (descartar silenciosamente), reject (descartar com resposta ICMP), jump (saltar para outra chain e retornar), goto (saltar sem retorno) e return (retornar da chain atual).

4. Políticas de segurança: estado e conexão

O rastreamento de conexão é essencial para firewalls stateful. O nftables usa a expressão ct state para classificar pacotes:

# Aceitar conexões já estabelecidas e relacionadas
nft add rule inet meu_firewall input ct state established,related accept

# Aceitar novas conexões SSH
nft add rule inet meu_firewall input ct state new tcp dport 22 accept

# Bloquear pacotes inválidos
nft add rule inet meu_firewall input ct state invalid drop

# Regra completa para forward chain (roteamento)
nft add rule inet meu_firewall forward ct state established,related accept
nft add rule inet meu_firewall forward ct state new tcp dport 80 accept

A política de segurança deve sempre começar com drop nas chains de entrada e encaminhamento, permitindo apenas o tráfego explicitamente autorizado. Isso evita vazamentos de pacotes não solicitados.

5. Criação de conjuntos (sets) e mapas para escalabilidade

Conjuntos permitem agrupar múltiplos endereços ou portas em uma única regra, melhorando performance e legibilidade:

# Conjunto nomeado de IPs bloqueados
nft add set inet meu_firewall ip_bloqueados { type ipv4_addr \; }

# Adicionar IPs ao conjunto
nft add element inet meu_firewall ip_bloqueados { 10.0.0.5, 192.168.1.200 }

# Usar o conjunto em uma regra
nft add rule inet meu_firewall input ip saddr @ip_bloqueados drop

# Conjunto de portas permitidas
nft add set inet meu_firewall portas_permitidas { type inet_service \; }
nft add element inet meu_firewall portas_permitidas { ssh, http, https }
nft add rule inet meu_firewall input tcp dport @portas_permitidas accept

Mapas associam chaves a valores, úteis para NAT dinâmico:

# Mapa para DNAT condicional
nft add map inet meu_firewall nat_map { type ipv4_addr : ipv4_addr \; }
nft add element inet meu_firewall nat_map { 203.0.113.10 : 192.168.1.100 }
nft add rule nat prerouting ip daddr map @nat_map dnat to $map_value

6. Configuração de NAT (masquerade, DNAT, SNAT)

O NAT no nftables usa chains do tipo nat:

# Criar tabela e chain para NAT
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }

# Masquerading (para interfaces dinâmicas como PPPoE)
nft add rule ip nat postrouting meta oifname "ppp0" masquerade

# SNAT com IP fixo
nft add rule ip nat postrouting ip saddr 192.168.1.0/24 oif eth0 snat to 203.0.113.1

# DNAT (port forwarding)
nft add rule ip nat prerouting tcp dport 8080 dnat to 192.168.1.100:80

O masquerading é ideal para conexões com IP dinâmico, enquanto SNAT/DNAT são usados em cenários com IPs fixos.

7. Logging, depuração e monitoramento do firewall

Para registrar pacotes sem sobrecarregar o sistema, use limites:

# Log com limite de 3 mensagens por minuto
nft add rule inet meu_firewall input tcp dport 22 limit rate 3/minute log prefix "SSH_ATTEMPT: " drop

# Log de pacotes rejeitados
nft add rule inet meu_firewall input reject with icmp type admin-prohibited log prefix "REJEITADO: "

Comandos de monitoramento:

# Listar todo o ruleset
nft list ruleset

# Monitorar eventos em tempo real
nft monitor

# Adicionar contadores para auditoria
nft add rule inet meu_firewall input tcp dport 443 counter accept

Os contadores mostram o número de pacotes e bytes processados por cada regra, facilitando a análise de tráfego.

8. Boas práticas, persistência e automação

Para tornar as regras persistentes:

# Salvar ruleset atual
nft list ruleset > /etc/nftables.conf

# Restaurar ruleset
nft -f /etc/nftables.conf

# Ativar serviço systemd (Debian/Ubuntu)
sudo systemctl enable nftables
sudo systemctl start nftables

Estratégias de teste seguras:

# Criar chain de staging para testar regras
nft add chain inet meu_firewall staging

# Adicionar regras de teste
nft add rule inet meu_firewall staging tcp dport 22 accept

# Antes de aplicar, fazer backup
cp /etc/nftables.conf /etc/nftables.conf.bak

# Rollback rápido
nft -f /etc/nftables.conf.bak

Sempre teste regras em um ambiente não crítico antes de aplicar em produção. Use chains separadas para diferentes funcionalidades (ex: input_web, input_admin, forward_lan) para facilitar manutenção e depuração.

Referências