Outils pour utilisateurs

Outils du site


Ceci est une ancienne révision du document !


Nftables

Le couple Netfilter/Iptables dont le projet fut initié par Paul “Rusty” Russell au tout début du siècle. Si Netfilter reste d'actualité en évoluant au fil du temps, Iptables, de l'aveu même de son initiateur en était arrivé à un point où toute évolution devenait problématique, le code devenant difficile à maintenir et les commandes trop nombreuses (iptables, ip6tables, ebtables, arptables…).

Nftables, apparu depuis le kernel 3.13 en 2014, reprend toutes les idées accumulées dans le projet iptables, en les organisant de façon plus cohérente, avec un code entièrement revu.

La transition

De très nombreux pare-feu ont été mis en place en utilisant iptables. De très nombreux outils ont été développés, qui sont des surcouches d'Iptables pour aider à créer des protections contre les attaques comme fail2ban, Shorewall et bien d'autres. Certains de ces outils sont maintenant (04/2025) adaptés à Nftables, d'autres pas encore, ou ne le seront jamais. La transition ne peut donc se faire qu'en douceur.

Regardons comment Debian a traité le problème. La version stable au 03/04/2025 est la version «Bookworm» 12.10 (kernel 6.1) et elle installe Nftables par défaut. Cependant, le paquet IPtables existe toujours, dont la description est la suivante:

apt show iptables
Package: iptables
Version: 1.8.9-2
...
Description: outils d'administration pour le filtrage de paquets et le NAT
 Le cadriciel iptables/xtables a été remplacé par nftables. La migration doit être envisagée.
 .
 Iptables est le programme en ligne de commande pour l'espace utilisateur,
 utilisé pour configurer l'ensemble des règles de filtrage de paquets et
 de NAT sous Linux. Il est destiné aux administrateurs système et réseau.
 .
 Ce paquet fournit plusieurs utilitaires différents, dont les plus
 importants sont :
 .
 iptables-nft, iptables-nft-save, iptables-nft-restore (version basée sur nft)
 .
 iptables-legacy, iptables-legacy-save, iptables-legacy-restore (version traditionnelle)
 .
  ip6tables-nft, ip6tables-nft-save, ip6tables-nft-restore (version basée sur nft)
 .
 ip6tables-legacy, ip6tables-legacy-save, ip6tables-legacy-restore (version traditionnelle)
 .
 arptables-nft, arptables-nft-save, arptables-nft-restore (version basée sur nft)
 .
 ebtables-nft, ebtables-nft-save, ebtables-nft-restore (version basée sur nft)
Le paquet propose donc une sorte d'interprète iptables/Nftables, avec malgré tout les anciennes commandes iptables et ip6tables natives pour les irréductibles.

Iptables encore

Nous allons installer ce paquet qui ne l'est donc plus par défaut. Nous allons le faire sur la Debian «Trixie» encore à l'état “testing” au 03/04/2025.

apt install iptables

Installing:                                     
  iptables

Installing dependencies:
  libip4tc2  libip6tc2  libnetfilter-conntrack3  libnfnetlink0

Paquets suggérés :
  firewalld

Summary:
  Upgrading: 0, Installing: 5, Removing: 0, Not Upgrading: 0
  Download size: 458 kB
  Space needed: 2 799 kB / 8 040 MB available

Continue? [O/n] o

Réception de :1 http://deb.debian.org/debian trixie/main amd64 libip4tc2 amd64 1.8.11-2 [20,0 kB]
Réception de :2 http://deb.debian.org/debian trixie/main amd64 libip6tc2 amd64 1.8.11-2 [20,3 kB]
Réception de :3 http://deb.debian.org/debian trixie/main amd64 libnfnetlink0 amd64 1.0.2-3 [14,4 kB]
Réception de :4 http://deb.debian.org/debian trixie/main amd64 libnetfilter-conntrack3 amd64 1.1.0-1 [42,1 kB]
Réception de :5 http://deb.debian.org/debian trixie/main amd64 iptables amd64 1.8.11-2 [361 kB]
458 ko réceptionnés en 0s (1 646 ko/s)
Sélection du paquet libip4tc2:amd64 précédemment désélectionné.
(Lecture de la base de données... 36101 fichiers et répertoires déjà installés.)
Préparation du dépaquetage de .../libip4tc2_1.8.11-2_amd64.deb ...
Dépaquetage de libip4tc2:amd64 (1.8.11-2) ...
Sélection du paquet libip6tc2:amd64 précédemment désélectionné.
Préparation du dépaquetage de .../libip6tc2_1.8.11-2_amd64.deb ...
Dépaquetage de libip6tc2:amd64 (1.8.11-2) ...
Sélection du paquet libnfnetlink0:amd64 précédemment désélectionné.
Préparation du dépaquetage de .../libnfnetlink0_1.0.2-3_amd64.deb ...
Dépaquetage de libnfnetlink0:amd64 (1.0.2-3) ...
Sélection du paquet libnetfilter-conntrack3:amd64 précédemment désélectionné.
Préparation du dépaquetage de .../libnetfilter-conntrack3_1.1.0-1_amd64.deb ...
Dépaquetage de libnetfilter-conntrack3:amd64 (1.1.0-1) ...
Sélection du paquet iptables précédemment désélectionné.
Préparation du dépaquetage de .../iptables_1.8.11-2_amd64.deb ...
Dépaquetage de iptables (1.8.11-2) ...
Paramétrage de libip4tc2:amd64 (1.8.11-2) ...
Paramétrage de libip6tc2:amd64 (1.8.11-2) ...
Paramétrage de libnfnetlink0:amd64 (1.0.2-3) ...
Paramétrage de libnetfilter-conntrack3:amd64 (1.1.0-1) ...
Paramétrage de iptables (1.8.11-2) ...
update-alternatives: utilisation de « /usr/sbin/iptables-legacy » pour fournir « /usr/sbin/iptables » (iptables) en mode automatique
update-alternatives: utilisation de « /usr/sbin/ip6tables-legacy » pour fournir « /usr/sbin/ip6tables » (ip6tables) en mode automatique
update-alternatives: utilisation de « /usr/sbin/iptables-nft » pour fournir « /usr/sbin/iptables » (iptables) en mode automatique
update-alternatives: utilisation de « /usr/sbin/ip6tables-nft » pour fournir « /usr/sbin/ip6tables » (ip6tables) en mode automatique
update-alternatives: utilisation de « /usr/sbin/arptables-nft » pour fournir « /usr/sbin/arptables » (arptables) en mode automatique
update-alternatives: utilisation de « /usr/sbin/ebtables-nft » pour fournir « /usr/sbin/ebtables » (ebtables) en mode automatique
Traitement des actions différées (« triggers ») pour man-db (2.13.0-1) ...
Traitement des actions différées (« triggers ») pour libc-bin (2.41-6) ...
Faisons le point sur les alternatives1).
update-alternatives --config iptables

Il existe 2 choix pour l'alternative iptables (qui fournit /usr/sbin/iptables).

  Sélection   Chemin                     Priorité  État
------------------------------------------------------------
* 0            /usr/sbin/iptables-nft      20        mode automatique
  1            /usr/sbin/iptables-legacy   10        mode manuel
  2            /usr/sbin/iptables-nft      20        mode manuel

Appuyez sur  pour conserver le choix actuel [*], ou tapez le numéro de sélection : 
Qu'est-ce à dire ? Nous gardons l'alternative par défaut, à savoir utiliser iptables-nft justement sans le savoir obligatoirement. Pour vérifier et en même temps décortiquer le principe des alternatives:
which iptables
/usr/sbin/iptables

ls -l /usr/sbin/iptables
lrwxrwxrwx 1 root root 26 20 nov.  10:03 /usr/sbin/iptables -> /etc/alternatives/iptables

ls -l /etc/alternatives/iptables
lrwxrwxrwx 1 root root 22 26 mars  17:52 /etc/alternatives/iptables -> /usr/sbin/iptables-nft
Donc, un lien qui pointe vers un autre lien qui pointe vers la commande alternative. Bref, en gardant cette alternative, nous allons utiliser nftables sans le savoir, en utilisant toujours des règles de type iptables, ce qui permet de laisser du temps pour faire évoluer les outils annexes comme fail2ban qui sait désormais utiliser Nftables.

Premier pas

Écrivons quelques règles simples comme nous les avons déjà vues sur notre maquette précédente:

iptables -A INPUT -p tcp --dport 23 -j ACCEPT
iptables -A INPUT -p udp --dport 68 -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -P INPUT DROP

En français:

laisser entrer les connexions TCP sur le port 23 (Telnet)
laisser entrer les datagrammes  UDP sur le port 68 (DHCP)
laisser entrer toutes les connexions déjà établies ou relatives à une connexion déjà établie
mettre tout le reste à la poubelle

Pour IPv6 c'est un peu la même chose à part qu'il vaut mieux laisser passer ICMP vu la façon dont la configuration «sans état» se fait, de même que l'on peut faire confiance aux adresses de lien local,mais ne plus autoriser l'accès au port 23 pour les adresses «lien global»:

ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -j ACCEPT
ip6tables -A INPUT -s fe80::/64 -j ACCEPT
ip6tables -P INPUT DROP

Vérification:

iptables --list

Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:telnet
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootpc
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

ip6tables --list

Chain INPUT (policy DROP)
target     prot      opt source               destination         
ACCEPT     ipv6-icmp --  anywhere             anywhere            
ACCEPT     all       --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     all       --  fe80::/64            anywhere            


Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
Et puisque nous utilisons la traduction IPtables/Nftables, voyons si le nouvel outil «nft» s'y retrouve:

En mode interactif SVP!

 nft -i

nft> list tables
table ip filter
table ip6 filter

nft> list table ip filter
# Warning: table ip filter is managed by iptables-nft, do not touch!
table ip filter {
	chain INPUT {
		type filter hook input priority filter; policy drop;
		tcp dport 23 counter packets 1528 bytes 81891 accept
		udp dport 68 counter packets 0 bytes 0 accept
		ct state related,established counter packets 0 bytes 0 accept
	}
}

nft> list table ip6 filter
# Warning: table ip filter is managed by iptables-nft, do not touch!
table ip6 filter {
	chain INPUT {
		type filter hook input priority filter; policy drop;
		ct state related,established counter packets 0 bytes 0 accept
		meta l4proto ipv6-icmp counter packets 38 bytes 2704 accept
		ip6 saddr fe80::/64 counter packets 0 bytes 0 accept
	}
}
Nous sentons bien qu'en version «nft» ça veut dire la même chose, mais avec une syntaxe complètement différente qui ressemble déjà beaucoup à un fichier de configuration.

À priori, nous avons toujours deux tables séparées, pour IPv4 et pour IPv6, sauf que nft sait gérer les deux dans le même environnement:

nft list ruleset

# Warning: table ip filter is managed by iptables-nft, do not touch!
table ip filter {
	chain INPUT {
		type filter hook input priority filter; policy drop;
		tcp dport 23 counter packets 496 bytes 26436 accept
		ct state related,established counter packets 20 bytes 2060 accept
	}
}
# Warning: table ip6 filter is managed by iptables-nft, do not touch!
table ip6 filter {
		chain INPUT {
		type filter hook input priority filter; policy drop;
		ct state related,established counter packets 0 bytes 0 accept
		meta l4proto ipv6-icmp counter packets 28 bytes 1968 accept
		ip6 saddr fe80::/64 counter packets 0 bytes 0 accept
	}

Ce qui permet d'avoir beaucoup plus facilement une vue de l'ensemble du filtrage.

Il semble donc relativement simple de traduire des pare-feux iptables en pare-feux nftables, mais comme indiqué dans le «warning»: il faudra choisir son camp une fois pour toutes si l'on doit modifier quelque chose par la suite.

Migration

Sur cette première manip, essayons de migrer définitivement vers Nftables.

Sauvegarde des règles iptables

iptables-save > rules-v4-Iptables.txt
ip6tables-save > rules-v6-Iptables.txt

Le lecteur attentif aura remarqué que dans ce cas simple les règles sont identiques en IPv4 et IPv6 et que donc la seconde ligne est inutile. Mais dans le cas général, les règles IPv4 et IPv6 ne sont pas forcément les mêmes!

Traduire ces règles en syntaxe nft

iptables-restore-translate -f rules-v4-Iptables.txt > ruleset.nft
ip6tables-restore-translate -f rules-v6-Iptables.txt >> ruleset.nft

À l'issue de cette étape, le fichier ruleset.nft a donc cette allure:

cat ruleset.nft 

# Translated by iptables-restore-translate v1.8.11 on Thu Mar 27 11:32:55 2025
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; policy drop; }
add chain ip filter FORWARD { type filter hook forward priority 0; policy accept; }
add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }
add rule ip filter INPUT tcp dport 23 counter accept
add rule ip filter INPUT ct state related,established counter accept
# Completed on Thu Mar 27 11:32:55 2025
# Translated by ip6tables-restore-translate v1.8.11 on Thu Mar 27 11:33:15 2025
add table ip6 filter
add chain ip6 filter INPUT { type filter hook input priority 0; policy drop; }
add chain ip6 filter FORWARD { type filter hook forward priority 0; policy accept; }
add chain ip6 filter OUTPUT { type filter hook output priority 0; policy accept; }
add rule ip6 filter INPUT ct state related,established counter accept
add rule ip6 filter INPUT meta l4proto ipv6-icmp counter accept
add rule ip6 filter INPUT ip6 saddr fe80::/64 counter accept
# Completed on Thu Mar 27 11:33:15 2025

Création du fichier de configuration nftables

Très simple. On commence par virer les éventuels parasites, puis on injecte notre fichier de traduction:

nft flush ruleset

nft -f ruleset.nft
Et l'on admire le résultat:
nft list ruleset

table ip filter {
	chain INPUT {
		type filter hook input priority filter; policy drop;
		tcp dport 23 counter packets 35 bytes 1837 accept
		ct state established,related counter packets 0 bytes 0 accept
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
	}
}
table ip6 filter {
	chain INPUT {
		type filter hook input priority filter; policy drop;
		ct state established,related counter packets 0 bytes 0 accept
		meta l4proto ipv6-icmp counter packets 2 bytes 200 accept
		ip6 saddr fe80::/64 counter packets 0 bytes 0 accept
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
	}
}
Le système a rajouté les chaînes INPUT et FORWARD qui restent vides dans notre cas (trop) simple. En effet, il a été omis d'autoriser les entrées et les sorties sur l'interface locale, aussi bien en IPv4 qu'en IPv6, ce qui pourrait perturber le fonctionnement de certains services utilisant un socket inet plutôt qu'un socket unix pour communiquer entre eux.

Franchir le Rubicon

Il faut maintenant activer le service nftables et ne plus jamais utiliser les outils iptables!

systemctl enable nftables.service
systemctl start nftables.service
apt purge iptables

En français:

  • activer le service nftables sur systemd,
  • démarrer ce service,
  • virer tout ce qu'avait installé le paquet Iptables.

Autrement-dit, si ça a foiré, il faudra tout reprendre à zéro, d'où l'intérêt d'y aller prudemment.

Ajustement utile

Par curiosité, regardons ce que fait le service «nftables» de systemd. Le script se trouve dans /usr/lib/systemd/system/:

cat /usr/lib/systemd/system/nftables.service 
[Unit]
Description=nftables
Documentation=man:nft(8) http://wiki.nftables.org
Wants=network-pre.target
Before=network-pre.target shutdown.target
Conflicts=shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
RemainAfterExit=yes
StandardInput=null
ProtectSystem=full
ProtectHome=true
ExecStart=/usr/sbin/nft -f /etc/nftables.conf
ExecReload=/usr/sbin/nft -f /etc/nftables.conf
ExecStop=/usr/sbin/nft flush ruleset

[Install]
WantedBy=sysinit.target

  • au démarrage (ou au re-démarrage) le fichier /etc/nftables.conf sera chargé;
  • à l'arrêt, la configuration est simplement détruite, mais pas sauvée.

Il revient donc à l'administrateur de maintenir à jour ce fichier /etc/nftables.conf.

Si l'on recharge le fichier de configuration, les règles vont s'inscrire une fois de plus dans les chaînes. Il faut donc penser à nettoyer avant. Il est donc nécessaire de retoucher un peu le script de ce service. La procédure propre est prévue:

  1. copier le fichier original dans /etc/systemd en respectant l'arborescence,
  2. modifier cette copie en fonction des besoins. Ainsi

cp /usr/lib/systemd/system/nftables.service /etc/systemd/system/
puis modifier cette copie comme ceci:
[Unit]
Description=nftables
Documentation=man:nft(8) http://wiki.nftables.org
Wants=network-pre.target
Before=network-pre.target shutdown.target
Conflicts=shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
RemainAfterExit=yes
StandardInput=null
ProtectSystem=full
ProtectHome=true
ExecStart=/usr/sbin/nft flush ruleset
ExecStart=/usr/sbin/nft -f /etc/nftables.conf
ExecReload=/usr/sbin/nft flush ruleset
ExecReload=/usr/sbin/nft -f /etc/nftables.conf
ExecStop=/usr/sbin/nft flush ruleset

[Install]
WantedBy=sysinit.target
De cette manière, lorsque l'administrateur aura modifié au moyen de la commande nft les règles de filtrage, une fois sa modification validée, il devra mettre à jour le fichier /etc/nftables.conf de manière à assurer la persistance de ces règles aussi bien au redémarrage du service qu'à celui de tout le système.

Vérification

Il reste à confirmer que tout ceci fonctionne comme prévu. Après redémarrage du prototype:

systemctl status nftables
● nftables.service - nftables
     Loaded: loaded (/usr/lib/systemd/system/nftables.service; enabled; preset: enabled)
     Active: active (exited) since Thu 2025-04-03 11:28:22 CEST; 5h 1min ago
...
nft list ruleset
table inet filter {
	chain input {
		type filter hook input priority filter; policy accept;
	}

	chain forward {
		type filter hook forward priority filter; policy accept;
	}

	chain output {
		type filter hook output priority filter; policy accept;
	}
}
table ip filter {
	chain INPUT {
		type filter hook input priority filter; policy drop;
		tcp dport 23 counter packets 661 bytes 35402 accept
		ct state established,related counter packets 29 bytes 2996 accept
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
	}
}
table ip6 filter {
	chain INPUT {
		type filter hook input priority filter; policy drop;
		tcp dport 23 counter packets 0 bytes 0 accept
		ct state established,related counter packets 0 bytes 0 accept
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
	}
}

Reste à étudier la nouvelle syntaxe de manière à oublier Iptables.

1)
Debian propose ce moyen élégant pour rediriger une commande connue vers la vraie commande et suivant le cas, permet à l'administrateur de choisir, avec la commande update-alternatives.
Nftables: Dernière modification le: 05/04/2025 à 12:53 par prof