Aller au contenu
Sécurité medium

Configurer un pare-feu avec nftables

12 min de lecture

nftables est le pare-feu du noyau Linux moderne : c'est lui qui filtre réellement les paquets, sous UFW comme sous Firewalld. L'outil nft remplace iptables avec une syntaxe unifiée, des sets natifs et de meilleures performances. Ce guide s'adresse à ceux qui veulent écrire leurs règles directement en nftables, sans frontend : serveurs minimalistes, conteneurs, appliances, ou rulesets versionnés en IaC. Vous partirez d'un ruleset serveur complet, puis verrez les sets, le NAT et la persistance.

Si vous cherchez d'abord une prise en main simple, un frontend comme UFW ou Firewalld reste plus rapide. nftables direct s'adresse à qui veut le contrôle total.

  • La différence entre nftables et iptables et quand écrire du nft direct.
  • Les briques : tables, chaînes, hooks et politique par défaut.
  • Un ruleset serveur complet avec filtrage stateful.
  • Les sets pour gérer des listes d'adresses proprement.
  • Le NAT, le masquerade et le port forwarding.
  • Rendre le ruleset persistant au redémarrage.
  • Un serveur Linux récent (RHEL 8+, Debian 10+, Ubuntu 20.04+) et un accès root.
  • Les concepts de filtrage : politique par défaut, flux entrants/sortants, connexions à état. En cas de doute, voir Introduction aux pare-feux.
  • Un accès console de secours avant d'appliquer une politique drop sur un serveur distant.

iptables et nftables pilotent tous les deux Netfilter, le sous-système de filtrage du noyau. nftables est le successeur officiel : sur les distributions récentes, iptables n'est souvent qu'un wrapper (iptables-nft) qui traduit vers nftables en interne.

Critèreiptablesnftables
StatutLegacy, maintenu par compatibilitéStandard depuis Linux 3.13 (2014)
SyntaxeUne commande par table (iptables, ip6tables...)Une commande nft, IPv4 et IPv6 unifiés
Listes d'IPNécessite ipset en plusSets natifs
PerformanceRègles évaluées linéairementSets et maps en temps constant
ComptageCompteurs par défautCompteurs à la demande (plus rapide)

En clair : sur un système moderne, écrivez du nftables. iptables ne sert plus qu'à lire d'anciennes configurations ou à faire tourner des scripts legacy.

La règle générale reste d'utiliser le frontend par défaut de votre distribution (UFW sur Debian/Ubuntu, Firewalld sur RHEL). Mais nft direct est justifié dans plusieurs cas :

  • Serveur minimaliste ou conteneur où l'on ne veut aucun démon supplémentaire.
  • Ruleset versionné en Git et déployé par Ansible ou un script (infrastructure as code).
  • Règles avancées que les frontends exposent mal : maps, priorités de hooks, filtrage par intervalle.
  • Appliance ou passerelle où vous maîtrisez tout le trafic.

nftables est présent sur tous les noyaux récents ; seul l'outil nft et le service peuvent manquer.

Fenêtre de terminal
sudo apt update && sudo apt install -y nftables
sudo systemctl enable --now nftables
nft --version
# nftables v1.0.6 (Lester Gooch #5)

Trois notions structurent nftables. Une table est un conteneur de règles pour une famille de protocoles (inet couvre IPv4 et IPv6 d'un coup). Une chaîne regroupe des règles ; une chaîne dite de base s'accroche à un hook du noyau, un point de passage du paquet.

Les hooks principaux pour le filtrage et le NAT :

HookMomentUsage typique
inputPaquet destiné à la machineFiltrer les flux entrants
outputPaquet émis par la machineFiltrer les flux sortants
forwardPaquet routé à travers la machinePasserelle, routeur
preroutingAvant décision de routageDNAT, port forwarding
postroutingAprès routage, avant émissionSNAT, masquerade

Chaque chaîne de base porte une politique par défaut (policy drop ou policy accept) appliquée quand aucune règle n'a matché.

Voici un ruleset serveur complet en famille inet (IPv4 + IPv6). Il pose une politique drop par défaut, n'autorise que l'essentiel, et journalise le reste. Ce ruleset a été appliqué et vérifié sur nftables 1.0.6.

/etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ct state invalid drop
ip protocol icmp accept
tcp dport { 80, 443 } accept
tcp dport 22 accept
limit rate 5/minute log prefix "nft-drop: "
drop
}
chain forward { type filter hook forward priority filter; policy drop; }
chain output { type filter hook output priority filter; policy accept; }
}

Chaque ligne compte :

  • ct state established,related accept autorise les réponses aux connexions déjà ouvertes : c'est le cœur du filtrage stateful. Sans elle, votre serveur ne recevrait aucune réponse.
  • ct state invalid drop jette les paquets incohérents, souvent des scans.
  • tcp dport { 80, 443 } utilise une liste anonyme : plus lisible qu'une règle par port.
  • limit rate 5/minute log journalise les paquets bloqués sans inonder les logs.

Validez toujours avant d'appliquer, avec l'option -c (check) qui ne charge rien :

Fenêtre de terminal
sudo nft -c -f /etc/nftables.conf # validation seule
sudo nft -f /etc/nftables.conf # application
sudo nft list ruleset # vérification

Un set est une liste nommée, évaluée en temps constant. C'est l'équivalent natif d'ipset, idéal pour une allowlist d'administration.

Fenêtre de terminal
table inet filter {
set ssh_autorises {
type ipv4_addr
elements = { 192.168.1.10, 10.0.0.5 }
}
chain input {
type filter hook input priority filter; policy drop;
# ... règles précédentes ...
tcp dport 22 ip saddr @ssh_autorises accept
}
}

La règle ip saddr @ssh_autorises n'accepte le SSH que depuis les adresses du set. Ajouter une IP ne demande pas de recharger tout le ruleset :

Fenêtre de terminal
sudo nft add element inet filter ssh_autorises { 203.0.113.7 }

Les maps vont plus loin en associant une clé à une valeur (par exemple un port à une décision), utiles pour du routage de règles compact.

Pour qu'une passerelle partage sa connexion, ajoutez une table nat avec une chaîne postrouting. Le masquerade réécrit l'adresse source des paquets sortants avec l'IP de l'interface, la forme de SNAT adaptée aux IP dynamiques.

Fenêtre de terminal
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "eth0" masquerade
}
}

N'oubliez pas d'activer le routage du noyau, sinon les paquets ne traversent pas la machine :

Fenêtre de terminal
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-forward.conf
sudo sysctl --system

Pour rediriger un port public vers un service interne, utilisez une chaîne prerouting avec dnat. Testé sur nftables 1.0.6 :

Fenêtre de terminal
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
tcp dport 8080 dnat to 192.168.1.20:80
}
}

Ici, tout le trafic arrivant sur le port 8080 est réécrit vers 192.168.1.20:80. Combinez prerouting (DNAT) et postrouting (masquerade) pour une passerelle complète.

Un ruleset chargé avec nft disparaît au redémarrage. Deux réflexes le rendent permanent.

  1. Écrire le ruleset dans /etc/nftables.conf (le fichier lu par le service), en le commençant par flush ruleset pour repartir propre.

  2. Activer le service qui recharge ce fichier au démarrage :

    Fenêtre de terminal
    sudo systemctl enable --now nftables
  3. Vérifier après un reboot que les règles sont bien là :

    Fenêtre de terminal
    sudo nft list ruleset

Comme le fichier est un script texte, versionnez-le dans Git et déployez-le par Ansible : c'est tout l'intérêt de nftables direct en infrastructure as code.

Docker écrit ses propres règles dans Netfilter pour publier les ports des conteneurs. Un flush ruleset manuel efface ces règles et casse le réseau des conteneurs jusqu'au prochain redémarrage du démon Docker.

La bonne pratique : laissez Docker gérer ses chaînes, et placez vos règles dans une table séparée plutôt que de vider le ruleset global. Sur une passerelle qui héberge aussi des conteneurs, cloisonnez avec soin et testez après chaque changement.

Les commandes du quotidien pour inspecter et modifier un ruleset actif.

Fenêtre de terminal
sudo nft list ruleset # tout le ruleset
sudo nft -a list ruleset # avec les handles (pour supprimer)
sudo nft list table inet filter # une table précise
sudo nft add rule inet filter input tcp dport 8443 accept
sudo nft delete rule inet filter input handle 12 # via le handle
sudo nft flush ruleset # tout effacer (attention !)
SymptômeCause probableSolution
Verrouillé hors du serveurpolicy drop sans règle SSHAccès console, ajouter la règle port 22
Aucune réponse aux requêtesPas de règle ct state establishedAutoriser established,related
Règles perdues au rebootRuleset non persistantÉcrire /etc/nftables.conf + activer le service
Conteneurs Docker injoignablesflush ruleset a effacé les chaînes DockerRedémarrer docker, isoler vos règles
Paquets bloqués invisiblesPas de journalisationAjouter une règle log prefix avant drop
  • nftables est le moteur de filtrage de tous les Linux modernes ; iptables n'est plus qu'un wrapper.
  • Structure : tables (familles), chaînes accrochées à des hooks, politique par défaut.
  • Un bon ruleset serveur est stateful (ct state established,related) et drop par défaut.
  • Les sets remplacent ipset pour les listes d'adresses ; les maps vont plus loin.
  • NAT en postrouting (masquerade), port forwarding en prerouting (dnat).
  • Rendez le ruleset persistant via /etc/nftables.conf et le service nftables.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn