CyberSDF

Reprenez la main sur votre numérique

nftables : faire survivre les règles du pare-feu au redémarrage

une machine de bureau ouverte posee sur un etabli, cables ranges, tournevis pose a plat

Après un redémarrage, nft list ruleset ne renvoie plus rien : une règle créée par nft add rule vit dans le noyau et n’existe dans aucun fichier. Sous Debian 12 (paquet nftables 1.0.6-2+deb12u2) comme sous Debian 13 (paquet nftables 1.1.3-1), la reprise au démarrage est le travail de l’unité nftables.service, dont la directive ExecStart vaut /usr/sbin/nft -f /etc/nftables.conf, et de ce seul fichier. Trois gestes décident du résultat : garder flush ruleset en tête du fichier, le valider avec nft -c -f, puis activer l’unité par systemctl enable nftables.

Sommaire
  1. Le paquet Debian livre /etc/nftables.conf exécutable, avec un shebang et flush ruleset
  2. Cinq étapes mènent de la règle tapée au terminal au pare-feu actif après un redémarrage
  3. Un ruleset enregistré par nft list ruleset s’empile au lieu de remplacer
  4. systemctl status nftables répond active (exited) même quand le pare-feu est vide
  5. Debian 11 livre priority 0 là où Debian 12 et 13 livrent priority filter
  6. Six arbitrages décident ce qui se passe au prochain démarrage

Le paquet Debian livre /etc/nftables.conf exécutable, avec un shebang et flush ruleset

Le fichier /etc/nftables.conf appartient au paquet, qui le déclare comme conffile : dpkg prévient si une mise à jour tente de le remplacer, et la copie locale reste prioritaire. Contenu livré par le paquet Debian 12 (nftables 1.0.6-2+deb12u2), identique à celui du paquet Debian 13 :

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
	chain input {
		type filter hook input priority filter;
	}
	chain forward {
		type filter hook forward priority filter;
	}
	chain output {
		type filter hook output priority filter;
	}
}

Trois détails pèsent sur la suite. Le fichier est livré avec les droits 755, donc exécutable directement, même si l’unité systemd passe par nft -f. La ligne flush ruleset vide les tables déjà présentes dans le noyau, et la page nft(8) de Debian 12 rappelle qu’un ruleset vidé laisse passer tout paquet valide ; chargée depuis le fichier, cette ligne s’exécute dans la même transaction que les tables suivantes. La même page précise que la sortie de list ruleset est conçue pour resservir en entrée de nft -f, comme iptables-save alimentait iptables-restore.

Cinq étapes mènent de la règle tapée au terminal au pare-feu actif après un redémarrage

  1. Vérifier le paquet et l’état de l’unité. Le paquet n’active pas le service à l’installation : le script postinst ne relance l’unité que si elle était déjà activée, et le wiki Debian demande explicitement systemctl enable nftables.service après l’installation.

    nft -v
    systemctl is-enabled nftables
    

    À l’écran : nftables v1.0.6 (Lester Gooch #5) sur Debian 12, et disabled tant que rien n’a été activé. Sur Debian 13, la première ligne annonce 1.1.3.

  2. Écrire le ruleset dans /etc/nftables.conf.

    sudo nano /etc/nftables.conf
    

    Un fichier minimal qui garde la boucle locale, les connexions établies, le ping IPv4 et IPv6, et le SSH, tout en refusant le reste :

    #!/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
    		meta l4proto { icmp, ipv6-icmp } accept
    		tcp dport 22 accept
    	}
    	chain forward {
    		type filter hook forward priority filter; policy drop;
    	}
    	chain output {
    		type filter hook output priority filter; policy accept;
    	}
    }
    

    À l’écran : rien de particulier à l’enregistrement, puis cat /etc/nftables.conf renvoie le contenu ci-dessus, première ligne #!/usr/sbin/nft -f comprise. La famille inet couvre IPv4 et IPv6 dans la même table : une politique drop sans les règles ICMP ci-dessus coupe IPv6.

  3. Valider la syntaxe sans rien appliquer. L’option -c, documentée comme Check commands validity without actually applying the changes, teste le fichier sans toucher au noyau.

    sudo nft -c -f /etc/nftables.conf
    echo $?
    

    À l’écran : aucune sortie, puis 0. Une faute fait échouer la commande et n’applique rien. Le format du message est celui que la page nft(8) de Debian 12 illustre par cet exemple, le passage fautif étant souligné par des accents circonflexes :

    <cmdline>:1:19-22: Error: Interface does not exist
    filter output oif eth0
    ^^^^

    Quand l’entrée vient d’un fichier, le préfixe devient le chemin de ce fichier, du type /etc/nftables.conf:12:3-16, suivi du motif du refus.

  4. Activer l’unité et démarrer le chargement.

    sudo systemctl enable --now nftables
    systemctl status nftables --no-pager
    nft list ruleset
    

    À l’écran : une ligne Created symlink /etc/systemd/system/sysinit.target.wants/nftables.service → /usr/lib/systemd/system/nftables.service., le paquet Debian 12 déposant l’unité dans /lib/systemd/system, /lib étant un lien vers /usr/lib ; puis Active: active (exited) ; puis les tables du fichier, à commencer par table inet filter. Un état failed à la place de active (exited) signale un fichier refusé, et sudo journalctl -u nftables -b affiche le message exact, comme l’expliquent les journaux des services systemd.

  5. Redémarrer la machine et contrôler le résultat.

    sudo systemctl reboot
    

    Après reconnexion :

    systemctl is-enabled nftables
    systemctl status nftables --no-pager
    nft list ruleset
    

    À l’écran : enabled, puis Active: active (exited), puis les mêmes tables qu’avant le redémarrage, sans une règle de plus. L’unité appartient à la cible sysinit.target et passe avant network-pre.target.

Un ruleset enregistré par nft list ruleset s’empile au lieu de remplacer

Remplacer /etc/nftables.conf par une copie de nft list ruleset casse la logique de remplacement. La sortie de cette commande ne contient que les tables, les chaînes et les règles : ni shebang, ni flush ruleset, qui ne sont pas des objets du noyau. Le wiki nftables écrit qu’un fichier réinjecté sans ligne de vidage ajoute les règles une seconde fois, à chaque rechargement. Le symptôme reste discret : nft list ruleset montre deux fois la même règle après un systemctl reload nftables.

sudo cp /etc/nftables.conf /etc/nftables.conf.bak
sudo sh -c 'echo "flush ruleset" > /etc/nftables.conf'
sudo sh -c 'nft -s list ruleset >> /etc/nftables.conf'
sudo nft -c -f /etc/nftables.conf
sudo systemctl reload nftables

L’option -s, ou –stateless, retire l’état des compteurs, et les variables déclarées par define sont remplacées par leur valeur dans la sortie.

systemctl status nftables répond active (exited) même quand le pare-feu est vide

L’unité est de type oneshot avec RemainAfterExit=yes : systemd exécute nft -f une fois, retient le code de sortie et laisse l’unité active. Deux conséquences surprennent. Modifier /etc/nftables.conf ne change rien au filtrage en cours, le fichier n’étant lu qu’au démarrage, au rechargement et au redémarrage du service : nft list ruleset dit la vérité, pas l’état de l’unité. Et systemctl stop nftables exécute la directive ExecStop, soit /usr/sbin/nft flush ruleset, qui supprime toutes les tables du noyau, y compris celles posées par Docker ou par la couche iptables-nft. Le wiki Debian recommande firewalld pour coordonner plusieurs outils qui écrivent dans le pare-feu.

systemctl cat nftables
nft list ruleset

À l’écran, la première commande affiche l’unité installée avec ses directives ExecStart, ExecReload et ExecStop, identiques dans les paquets Debian 11, 12 et 13.

Debian 11 livre priority 0 là où Debian 12 et 13 livrent priority filter

Les paquets Debian 11, 12 et 13 embarquent la même unité systemd mais pas le même exemple de configuration : la ligne de priorité des chaînes a changé de notation entre Debian 11 et Debian 12. La page nft(8) publiée par Debian pour la version 1.0.6 rappelle que le paramètre priority accepte un entier signé ou un nom standard, et donne filter pour valeur 0 : les deux écritures désignent la même position.

Version de Debian Paquet nftables Ligne livrée pour la chaîne input
Debian 11 (bullseye) 0.9.8-3.1+deb11u2 type filter hook input priority 0;
Debian 12 (bookworm) 1.0.6-2+deb12u2 type filter hook input priority filter;
Debian 13 (trixie) 1.1.3-1 type filter hook input priority filter;

D’une machine à l’autre, aucune retouche n’est nécessaire sur cette ligne, et le test nft -c -f sur la machine de destination tranche en quelques secondes. Ces règles forment la base d’un durcissement minimal.

Le contrôle qui tranche tient en une commande : après le démarrage suivant, nft list ruleset doit afficher table inet filter avec sa politique drop, sinon le fichier n’a pas été lu et journalctl -u nftables -b en donne la raison. La rubrique Debian regroupe les autres contrôles du même genre.

Six arbitrages décident ce qui se passe au prochain démarrage

Le service garde-t-il un processus en mémoire après le démarrage ?

Non. nftables.service est de type oneshot avec RemainAfterExit=yes : systemd retient le code de sortie et laisse l’unité active (exited), sans processus résident. Les règles vivent dans le noyau, qui les évalue seul. Le paquet reste léger : 176 Kio installés sous Debian 12 (nftables 1.0.6-2+deb12u2) et 185 Kio sous Debian 13 (1.1.3-1).

systemctl reload nftables ou systemctl restart nftables ?

Reload exécute ExecReload, soit nft -f /etc/nftables.conf, sans arrêter l’unité : le fichier remplace le ruleset en une transaction unique, sans trou de filtrage. Restart passe d’abord par ExecStop, soit nft flush ruleset, puis recharge : entre les deux opérations, le noyau ne filtre plus rien. Sur une session SSH, préférez reload, qui exige une unité déjà active.

Comment enregistrer le ruleset en cours dans /etc/nftables.conf ?

Sauvegardez la copie actuelle, écrivez flush ruleset en première ligne du nouveau fichier, ajoutez la sortie de nft -s list ruleset, puis contrôlez avec nft -c -f avant de recharger. Sans la ligne de vidage, chaque rechargement empile les règles au lieu de les remplacer. La sauvegarde préalable évite de perdre un fichier écrit à la main, la sortie de nft ne restituant ni les commentaires ni les variables.

Une politique drop peut-elle couper l’accès SSH ?

Oui, dès qu’une chaîne input passe en policy drop sans accepter les connexions établies : la règle ct state established,related accept et l’ouverture du port 22 doivent précéder la politique par défaut. Le chargement du fichier est atomique, une faute de syntaxe laisse donc l’ancien ruleset en place, mais un fichier valide qui refuse tout s’applique immédiatement. Gardez une seconde session ouverte pendant l’essai, et sachez qu’une machine devenue muette se répare sur la console.

Comment ajouter un fichier de règles séparé, par exemple pour un script maison ?

La page nft(8) de Debian 12 documente l’instruction include : une ligne include "/etc/nftables.d/*.nft" placée à la fin de /etc/nftables.conf charge tous les fichiers correspondants. Les jokers sont développés par ordre alphabétique, les fichiers dont le nom commence par un point sont ignorés, et une inclusion sans correspondance ne provoque aucune erreur. Le répertoire /etc/nftables.d n’est pas fourni par le paquet : il faut le créer avant de s’en servir.

Que devient le fichier local lors d’une mise à jour du paquet ?

/etc/nftables.conf est un conffile : si la nouvelle version du paquet le modifie et que la copie locale a changé, dpkg demande quelle version garder. Le script postinst du paquet 1.1.3-1 termine la mise à niveau par un try-restart de nftables.service, qui ne relance l’unité que si elle tournait déjà : les règles sont relues au passage, sans activation nouvelle.