Vous déployez un hôte Debian 13 propre, ouvrez le port dont vous avez besoin, et tout fonctionne. Puis une semaine plus tard,
une mise à jour anodine de paquet arrive, un runtime de conteneurs se met à jour, ou quelqu’un « ajoute juste une règle iptables vite fait »,
et soudain votre pare-feu devient une maison hantée. Le trafic chute. Les logs mentent. La moitié des commandes n’affichent rien.
Ce qui se passe n’est pas surnaturel. Ce sont deux interfaces (iptables et nftables) qui essaient de gérer les mêmes
hooks Netfilter, souvent via des couches de compatibilité, parfois directement, et occasionnellement un tiers
(Docker, Kubernetes, UFW, firewalld) qui choisit aléatoirement un camp. Le résultat : une guerre silencieuse des pare-feux : des règles existent,
mais pas là où vous regardez.
Le vrai problème : un noyau, plusieurs plans de contrôle
Sur Debian 13, vous pouvez avoir :
- nftables qui gère les règles directement via
nftetnftables.service - iptables en tant que commandes qui peuvent être :
- iptables-nft : le CLI iptables traduisant en règles nft
- iptables-legacy : l’ancien backend iptables utilisant les interfaces noyau legacy
- Un ou plusieurs gestionnaires de plus haut niveau : UFW, firewalld, Docker, Kubernetes, Podman, fail2ban
Aucun de ces éléments n’est intrinsèquement « mauvais ». Le mode de défaillance survient quand vous supposez qu’ils regardent tous la même
base de règles. Ils ne le font pas. Parfois ils regardent des backends différents. Parfois ils écrivent dans le même backend mais dans des tables/chaînes différentes avec des priorités auxquelles vous ne vous attendiez pas. Parfois vos règles sont correctes et les paquets ne les atteignent jamais à cause de offload, bridging, routage politique, ou conntrack qui change la donne.
Le péché opérationnel est de laisser deux autorités gérer la politique du pare-feu. Les pare-feux sont comme le contrôle des changements : vous n’avez
droit qu’à un seul patron.
Faits et historique : pourquoi on en est arrivés là
Quelques faits concrets vous aident à déboguer plus vite, car ils expliquent pourquoi « iptables dit X » peut être dénué de sens sur un système moderne.
- Netfilter est le cadre noyau ; iptables et nftables sont des interfaces utilisateur. La bataille se situe surtout en espace utilisateur, mais la douleur est dans le chemin du paquet.
- nftables a été introduit pour remplacer iptables. Il unifie IPv4/IPv6, supporte mieux les sets/maps, et réduit l’explosion de règles dans les cas courants.
- iptables-nft existe pour que les outils legacy continuent de fonctionner. Il traduit les commandes iptables en règles nftables, mais le mapping n’est pas toujours « transparent » lorsque vous inspectez.
- iptables-legacy peut toujours être installé et sélectionné. Sur un hôte où certains composants utilisent legacy et d’autres nft, vous êtes assuré de confusion et de divergences occasionnelles de règles.
- UFW parlait historiquement iptables. Certains environnements ajoutent UFW sur un système nftables en supposant qu’il devient « le pare-feu ». Parfois c’est vrai. Parfois c’est un second pare-feu.
- firewalld a évolué vers des backends nftables. Mais pas toutes les versions ni toutes les distributions par défaut, et « quel backend est actif » compte.
- Docker a popularisé la programmation automatique d’iptables. Il installera des règles NAT et filter sauf indication contraire, et il attend la sémantique iptables même quand le backend est nft.
- Kubernetes suppose traditionnellement la disponibilité d’iptables. Beaucoup de plugins CNI manipulent encore des règles iptables ; sur des backends nft cela marche généralement — jusqu’à ce que ça ne marche plus.
- La priorité des chaînes nftables est une notion de première classe. Dans iptables, l’ordre des chaînes intégrées est plutôt fixe. Dans nftables, vous pouvez créer plusieurs chaînes sur le même hook avec des priorités ; c’est puissant et c’est un excellent moyen de se tirer une balle dans le pied.
Voici la citation de fiabilité à garder sur un post-it :
« L’espoir n’est pas une stratégie. » — Gene Kranz
Playbook de diagnostic rapide (faire ça en premier)
Quand des paquets sont perdus ou que des ports semblent « ouverts mais injoignables », ne commencez pas par éditer les règles. Commencez par prouver qui possède le pare-feu et où les paquets sont évalués.
1) Identifier le plan de contrôle actif du pare-feu
- Vérifiez si nftables est chargé et si le service est activé/actif.
- Vérifiez quel backend iptables votre système utilise (nft vs legacy).
- Vérifiez si Docker/Kubernetes/UFW/firewalld sont installés et manipulent des règles.
2) Inspecter les règles effectives du noyau, pas vos hypothèses
- Dump du ruleset complet nft.
- Liste des règles iptables avec compteurs.
- Recherche de chaînes dupliquées ou conflictuelles (surtout NAT) et de politiques par défaut inattendues.
3) Valider le flux de paquets avec compteurs et captures ciblées
- Utilisez les compteurs (iptables
-v, nftcounter). - Utilisez
conntrackpour vérifier l’état. - Utilisez
tcpdumpen entrée et sortie pour voir où ça meurt.
4) Changez la politique uniquement ensuite
- Choisissez un seul gestionnaire et un seul backend.
- Supprimez ou désactivez les autres gestionnaires.
- Rendez la politique persistante et testez le comportement au reboot.
Blague n°1 : Les pare-feux sont comme les cuisines de bureau — tout le monde pense qu’il « aide juste », et ensuite rien ne fonctionne et ça sent le rance.
Un modèle mental pratique : iptables, nftables et le noyau
Le noyau a un chemin de paquet avec des hooks bien définis : ingress, prerouting, input, forward, output, postrouting (simplifiant un peu).
Netfilter fournit ces hooks. Les programmes utilisateurs créent des règles qui s’attachent à ces hooks. L’important : il peut y avoir plusieurs
jeux de règles et plusieurs chaînes attachées au même hook, et elles s’exécutent dans l’ordre.
iptables (classique) est organisé en tables (filter, nat, mangle, raw, security) et en chaînes intégrées (INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING).
nftables est plus flexible : vous créez des tables et des chaînes, puis déclarez quel hook et quelle priorité chaque chaîne utilise.
Sur Debian 13, la réalité opérationnelle la plus courante est :
- Votre commande
iptablesest en fait iptables-nft par défaut, écrivant dans nftables en coulisses. nft list rulesetest la vérité terrain pour les règles en vigueur (si vous êtes sur le backend nft).- Si vous basculez accidentellement vers iptables-legacy pour un composant, vous pouvez avoir « deux pare-feux différents », rapportant tous deux un succès.
Le schéma de conflit ressemble à ceci :
- Vous lancez
iptables -Set ne voyez « rien d’effrayant ». - Vous lancez
nft list rulesetet voyez une politique longue comme le bras que vous n’avez pas écrite. - Ou pire :
iptablesmontre une politique,nften montre une autre, et les paquets obéissent au backend réellement accroché.
Tâches pratiques : commandes, sorties, décisions
Les tâches ci‑dessous sont conçues pour être exécutées sur des hôtes Debian 13 lors d’un incident, d’une migration, ou d’un contrôle de santé.
Chaque tâche inclut : une commande, ce que signifie typiquement la sortie, et la décision à prendre ensuite. Ne survolez pas les décisions ; c’est là que les pannes s’arrêtent.
Task 1 — Identifier quel backend iptables est sélectionné
cr0x@server:~$ update-alternatives --display iptables
iptables - auto mode
link best version is /usr/sbin/iptables-nft
link currently points to /usr/sbin/iptables-nft
link iptables is /usr/sbin/iptables
slave iptables-restore is /usr/sbin/iptables-restore
slave iptables-save is /usr/sbin/iptables-save
/usr/sbin/iptables-legacy - priority 10
/usr/sbin/iptables-nft - priority 20
Ce que cela signifie : Si « currently points to iptables-nft », alors les commandes iptables se traduisent en nftables.
Si ça pointe vers iptables-legacy, vous utilisez le backend legacy.
Décision : Choisissez un backend sur tout l’hôte. Pour Debian 13, privilégiez iptables-nft à moins d’avoir une contrainte forte pour legacy.
Les backends mixtes sont la cause des règles fantômes.
Task 2 — Vérifier si le service nftables est activé et actif
cr0x@server:~$ systemctl status nftables --no-pager
● nftables.service - nftables
Loaded: loaded (/lib/systemd/system/nftables.service; enabled; preset: enabled)
Active: active (exited) since Sun 2025-12-28 10:41:12 UTC; 2h 3min ago
Docs: man:nft(8)
man:nftables(8)
Process: 512 ExecStart=/usr/sbin/nft -f /etc/nftables.conf (code=exited, status=0/SUCCESS)
Main PID: 512 (code=exited, status=0/SUCCESS)
Ce que cela signifie : « active (exited) » est normal ; il charge les règles puis quitte. « enabled » signifie que les règles seront chargées au démarrage depuis /etc/nftables.conf.
Décision : Si nftables est activé, considérez /etc/nftables.conf comme la source de vérité souhaitée — ou désactivez nftables si vous déléguez à un autre gestionnaire.
Task 3 — Dumper le ruleset effectif nft (vérité terrain)
cr0x@server:~$ nft list ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif "lo" accept
tcp dport { 22, 443 } accept
counter packets 10234 bytes 811234 drop
}
}
Ce que cela signifie : La politique effective pour inet filter input est drop, avec des règles d’accept explicites.
Le compteur sur la règle drop vous indique que des paquets la frappent.
Décision : Si votre port attendu n’est pas présent ici, arrêtez d’éditer des scripts iptables et corrigez le ruleset nft ou le gestionnaire qui le génère.
Task 4 — Voir les règles iptables avec compteurs (même sur backend nft)
cr0x@server:~$ iptables -L -n -v
Chain INPUT (policy DROP 120 packets, 9600 bytes)
pkts bytes target prot opt in out source destination
8123 640K ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
553 42012 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
102 6120 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
Ce que cela signifie : Si cette sortie correspond au ruleset nft, vous êtes probablement sur iptables-nft et voyez une vue traduite.
Si elle ne correspond pas à la sortie nft, vous pouvez avoir une situation de split-brain backend.
Décision : Si nft et iptables divergent, vérifiez immédiatement update-alternatives pour iptables et ip6tables, et auditez qui installe des règles.
Task 5 — Vérifier le backend ip6tables aussi (IPv6 est un lieu de surprises)
cr0x@server:~$ update-alternatives --display ip6tables
ip6tables - auto mode
link best version is /usr/sbin/ip6tables-nft
link currently points to /usr/sbin/ip6tables-nft
link ip6tables is /usr/sbin/ip6tables
slave ip6tables-restore is /usr/sbin/ip6tables-restore
slave ip6tables-save is /usr/sbin/ip6tables-save
/usr/sbin/ip6tables-legacy - priority 10
/usr/sbin/ip6tables-nft - priority 20
Ce que cela signifie : Vous pouvez être nft pour IPv4 et legacy pour IPv6 si quelqu’un « a corrigé une chose ». Ce n’est pas une correction ; c’est une bombe à retardement.
Décision : Alignez les backends IPv4 et IPv6. Si vous n’êtes pas prêt pour la politique IPv6, faites un drop explicite ou un allow explicite — n’« oubliez » pas son existence.
Task 6 — Trouver qui gère les règles du pare-feu (au niveau paquet)
cr0x@server:~$ dpkg -l | egrep 'nftables|iptables|ufw|firewalld|fail2ban|docker|kube|podman' | awk '{print $1,$2,$3}'
ii nftables 1.0.9-1
ii iptables 1.8.10-2
ii ufw 0.36.2-2
ii docker.io 26.0.2+dfsg1-1
ii fail2ban 1.1.0-1
Ce que cela signifie : L’hôte a plusieurs écrivains potentiels : UFW, Docker, fail2ban. Chacun peut ajouter ou recharger des règles.
Décision : Choisissez un « auteur de politique ». Si vous voulez une politique native nftables, configurez Docker/fail2ban en conséquence ou contraignez-les. Sinon, acceptez qu’ils possèdent des parties du ruleset.
Task 7 — Vérifier si Docker programme iptables
cr0x@server:~$ grep -R "iptables" /etc/docker/daemon.json 2>/dev/null || echo "no daemon.json iptables setting"
no daemon.json iptables setting
Ce que cela signifie : Le comportement par défaut est typiquement « Docker manipule iptables ». Que cela soit acceptable dépend de votre modèle.
Décision : Si vous avez besoin d’un contrôle strict via nftables, envisagez de configurer Docker "iptables": false et d’implémenter vous‑même les règles NAT/forwarding. Si vous n’avez pas le temps de le faire en toute sécurité, ne le faites pas à moitié.
Task 8 — Inspecter nftables pour des tables/chaînes créées par Docker
cr0x@server:~$ nft list tables
table inet filter
table ip nat
table ip filter
Ce que cela signifie : Voir table ip nat et table ip filter est normal, mais si vous ne les avez pas créées, quelque chose d’autre l’a fait.
Docker injecte communément des règles NAT.
Décision : Si un outil externe injecte des règles, documentez-le et surveillez-le. Le pire état est « automatisation inconnue ».
Task 9 — Vérifier les priorités de chaînes et hooks (problèmes d’ordre nftables)
cr0x@server:~$ nft -a list chain inet filter input
table inet filter {
chain input { # handle 5
type filter hook input priority 0; policy drop;
ct state established,related accept # handle 12
iif "lo" accept # handle 13
tcp dport 22 accept # handle 14
counter packets 10234 bytes 811234 drop # handle 20
}
}
Ce que cela signifie : Hook input priority 0. Si vous avez plusieurs chaînes attachées au même hook avec des priorités différentes,
vous devez connaître l’ordre car un drop dans une chaîne de priorité plus élevée peut empêcher des accept ultérieurs de s’exécuter.
Décision : Si plusieurs chaînes partagent un hook, consolidez-les ou documentez leurs priorités. « Deux chaînes sur le hook input » n’est pas automatiquement faux ; c’est automatiquement suspect.
Task 10 — Prouver que les paquets atteignent la règle attendue (compteurs)
cr0x@server:~$ nft list ruleset | sed -n '1,120p'
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif "lo" accept
tcp dport 443 counter packets 0 bytes 0 accept
counter packets 10234 bytes 811234 drop
}
}
Ce que cela signifie : Si votre compteur d’accept 443 reste à 0 tandis que les clients échouent à se connecter, soit le trafic n’arrive pas,
il arrive sur une interface/stack différente, soit il est droppé plus tôt (priorité, table raw, ingress), ou il s’agit d’un problème de routage.
Décision : Passez à la capture de paquets et aux vérifications de routage ; arrêtez d’éditer aveuglément des règles d’autorisation.
Task 11 — Confirmer le routage et l’écoute locale (pas un problème de pare-feu)
cr0x@server:~$ ss -lntp | egrep ':(22|443)\s'
LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=710,fd=3))
LISTEN 0 4096 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1188,fd=7))
Ce que cela signifie : Les services écoutent réellement. Si ceci est vide, le pare-feu est innocent et vous chassez le mauvais animal.
Décision : Si rien n’écoute, corrigez le service. Si ça écoute, continuez avec les vérifications pare-feu/routage.
Task 12 — Capture de paquets : le trafic atteint‑t‑il l’interface ?
cr0x@server:~$ sudo tcpdump -ni eth0 tcp port 443 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:55:12.112233 IP 203.0.113.10.52344 > 192.0.2.20.443: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0
10:55:13.112244 IP 203.0.113.10.52344 > 192.0.2.20.443: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 2 ecr 0,nop,wscale 7], length 0
Ce que cela signifie : Les SYN arrivent. Si vous ne voyez pas les SYN-ACK partir, c’est probablement un drop local, un routage local, ou le service qui ne répond pas.
Décision : Si le SYN arrive, vérifiez les compteurs nft/iptables et la politique à nouveau, ainsi que conntrack. Si le SYN n’arrive pas, vous êtes dans le domaine réseau (ACL en amont, routage, security groups, etc.).
Task 13 — Inspecter l’état conntrack pour un flux bloqué
cr0x@server:~$ sudo conntrack -L | head
tcp 6 431999 ESTABLISHED src=203.0.113.10 dst=192.0.2.20 sport=52344 dport=443 src=192.0.2.20 dst=203.0.113.10 sport=443 dport=52344 [ASSURED] mark=0 use=1
Ce que cela signifie : Conntrack voit des flux établis. Si vous voyez beaucoup de churn SYN_SENT ou TIME_WAIT,
cela indique des drops, du routage asymétrique, ou un refus applicatif.
Décision : Si conntrack montre des connexions établies mais que l’application échoue encore, suspectez l’application ou des problèmes MTU. Si conntrack montre des SYN sans achèvement, suspectez le pare-feu ou l’amont.
Task 14 — Vérifier une politique drop non voulue (politique par défaut nftables)
cr0x@server:~$ nft list chain inet filter input | sed -n '1,60p'
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif "lo" accept
tcp dport { 22 } accept
}
Ce que cela signifie : Drop par défaut et pas d’accept pour votre port. Ce n’est pas un bug ; c’est exactement ce que vous avez demandé, ou ce que quelqu’un a demandé en votre nom.
Décision : Ajoutez le port dans le plan de contrôle correct. Si un gestionnaire génère ce fichier, ne l’éditez pas à la main à moins d’aimer les surprises au reboot.
Task 15 — Détecter des règles legacy encore présentes (suspicion de split‑brain)
cr0x@server:~$ iptables-legacy -L -n -v 2>/dev/null | head
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Ce que cela signifie : Si legacy montre une politique différente de votre système actif basé sur nft, vous avez probablement des outils écrivant vers différents backends,
ou une configuration résiduelle qui mordra lors d’un basculement ou d’un reboot.
Décision : Si vous standardisez sur nft, purgez ou neutralisez l’utilisation legacy (alternatives et services). Si vous devez rester legacy, arrêtez d’utiliser le service nftables.
Task 16 — Auditer qui a touché l’état du pare-feu en dernier (logs)
cr0x@server:~$ journalctl -u nftables -u docker -u ufw --since "today" --no-pager | tail -n 30
Dec 28 09:01:10 server systemd[1]: Starting nftables...
Dec 28 09:01:10 server nft[512]: /etc/nftables.conf:23:3-45: Warning: deprecated syntax
Dec 28 09:01:10 server systemd[1]: Finished nftables.
Dec 28 09:14:22 server dockerd[844]: time="2025-12-28T09:14:22.012345678Z" level=info msg="Loading containers: done."
Dec 28 09:14:22 server dockerd[844]: time="2025-12-28T09:14:22.112345678Z" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16."
Ce que cela signifie : nftables s’est chargé au démarrage ; Docker s’est initialisé plus tard et a probablement installé des règles aussi. Cet ordre peut avoir de l’importance.
Décision : Si un service post‑boot écrase ou ajoute des règles, vous devez soit contrôler son comportement, soit intégrer ses attentes dans votre politique.
Trois mini-récits d’entreprise depuis le terrain
Mini-récit n°1 : L’incident causé par une mauvaise hypothèse
Une entreprise de taille moyenne standardisait sur Debian pour des reverse proxies en périphérie. Ils avaient une règle simple : « Tout est nftables maintenant ».
Quelqu’un a construit une politique nft simple, l’a mise dans /etc/nftables.conf, et a activé le service. Ça a passé la stagging.
Le déploiement était suffisamment calme pour que les gens se mettent à employer le mot « ennuyeux » comme compliment.
Quelques mois plus tard, une nouvelle équipe a ajouté un agent d’analyse interne qui « nécessite iptables ». Ils ont installé un paquet qui a tiré les outils iptables
et un script d’aide qui exécutait iptables -I INPUT -p tcp --dport 9100 -j ACCEPT au démarrage, parce que c’est ce qu’il faisait toujours sur les anciennes images.
Personne n’y a vraiment pensé. Ils ont vu la règle dans iptables -L. Ils l’ont même documentée dans le runbook.
Puis le premier incident réel : certains nœuds refusaient aléatoirement des connexions vers le port de l’exporter, mais seulement après des reboots.
Pendant l’appel d’incident, les gens répétaient sans cesse : « Mais iptables montre la règle d’accept ». C’était vrai — sur ces nœuds, iptables avait basculé en legacy à cause d’un changement d’alternatives.
Pendant ce temps nftables avait chargé une chaîne input par défaut en drop et n’a jamais vu la règle iptables.
La panne n’a pas été dramatique. Pas d’erreurs côté utilisateur. Juste des métriques manquantes, puis de mauvaises décisions d’autoscaling, puis des alarmes de capacité.
La leçon organisationnelle : l’équipe plateforme pensait « iptables est une vue legacy de nftables ». L’équipe appli pensait « iptables est le pare-feu ».
Les deux avaient tort, mais de manières différentes.
La correction a été brute : ils ont interdit l’usage ad‑hoc d’iptables sur ces hôtes, épinglé les alternatives sur iptables-nft, et écrit une méthode documentée pour ouvrir des ports :
une modification dans le repo nftables, revue comme du code. Ils ont aussi ajouté un contrôle CI qui compare nft list ruleset aux hooks de chaînes et aux politiques par défaut attendues.
Mini-récit n°2 : L’optimisation qui s’est retournée contre eux
Une autre équipe exploitait une plateforme de conteneurs très occupée sur des hôtes Debian. Ils cherchaient la latence, et un ingénieur a suggéré « simplifier les couches de pare-feu »
en désactivant la programmation iptables de Docker et en gérant tout directement dans nftables. Sur le papier, c’était propre : un seul fichier de politique, pas de surprises,
pas de chaînes aléatoires qui apparaissent.
Ils ont basculé le paramètre Docker "iptables": false et l’ont déployé progressivement. Ça a fonctionné en dev. Ça a fonctionné en stagging.
Puis la production a commencé à signaler des erreurs intermittentes « impossible de joindre un service externe » pour certains conteneurs, surtout après rotation de nœud.
L’instinct initial a été DNS. Le deuxième, le routage. Le troisième, blâmer l’application.
Le problème était le NAT et le forwarding. Docker faisait discrètement beaucoup de plomberie nécessaire : règles MASQUERADE, règles FORWARD accept pour les flux établis,
et un certain comportement d’isolation de bridge. Leur politique nft maison couvrait le chemin heureux mais manquait quelques cas limites, y compris le trafic depuis certains bridges
et les connexions hairpin. Conntrack a empiré les choses en rendant les échecs incohérents, selon l’état.
Ils ont récupéré en réactivant l’intégration iptables de Docker en production pendant qu’ils reconstruisaient la politique nft avec des exigences explicites pour le réseau des conteneurs.
L’« optimisation » en soi n’était pas mauvaise ; le plan de déploiement l’était. Ils ont traité la politique réseau comme un simple toggle de config au lieu d’un changement de conception système.
Leçon : si vous désactivez l’automatisation pare-feu d’un outil, vous héritez de ses responsabilités. Ce n’est pas intrinsèquement mauvais, mais ce n’est jamais gratuit.
Mini-récit n°3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une entreprise régulée exploitait des bastions Debian pour l’accès admin. Les règles étaient strictes : drop par défaut, listes d’autorisation explicites, et exigence que
chaque changement de pare-feu soit traçable. Leur équipe sécurité insistait pour que la politique soit déclarative, stockée dans un repo, et déployée par automatisation.
Tout le monde se plaignait. Puis ils s’y sont habitués.
Un jour une tempête de reboots de maintenance a frappé après une mise à jour du noyau. Plusieurs équipes ont signalé « SSH en panne » sur un sous‑ensemble de bastions.
Ça sentait le problème de pare-feu, car tout le reste était sain et le réseau hyperviseur semblait correct.
L’astreinte a pris la console hôte, lancé nft list ruleset, et comparé au dernier état connu bon du repo.
C’était identique. Les compteurs montraient que les SYN entrants étaient acceptés. Le pare-feu n’était pas coupable.
Le problème s’est avéré être un renommage d’interface mal ordonné qui a changé quelle interface correspondait aux règles d’autorisation.
Parce que la politique était déclarative, versionnée, et identique sur les hôtes, ils ont pu écarter la « dérive aléatoire » en quelques minutes.
Ça a raccourci l’incident et évité l’erreur classique : des gens ajoutant des règles d’urgence qui deviendraient ensuite des trous permanents et non documentés.
La pratique ennuyeuse n’était pas le repo. C’était la discipline de garder une source de vérité unique et de la tester au reboot.
C’est ainsi qu’on empêche un pare-feu de devenir de la tradition orale.
Arrêter la guerre : choisir un plan de contrôle et migrer proprement
Vous avez trois états finaux viables sur Debian 13. Deux sont sains. Un est un piège.
- État sain A : politique native nftables, gérée par
/etc/nftables.conf(ou un fichier généré), avec le service nftables activé. iptables utilisé seulement comme vue/compat (iptables-nft), pas comme auteur. - État sain B : un gestionnaire de haut niveau (firewalld ou UFW) est l’autorité unique, et tout le reste est configuré pour coopérer. Vous devez quand même savoir quel backend il utilise.
- Le piège : « Un peu de nftables, plus quelques règles iptables, plus Docker qui fait son truc, plus fail2ban qui ajoute une pincée. » Ce n’est pas une défense en profondeur. C’est la roulette opérationnelle.
Ce que je recommande pour la plupart des serveurs Debian 13
Si c’est un serveur que vous opérez comme infrastructure (VMs, bare metal, edge, bases de données, load balancers), privilégiez nftables-native.
C’est cohérent, inspectable et scriptable. Ensuite décidez comment gérer l’outillage conteneur :
- Si l’hôte exécute des conteneurs et que vous voulez une sécurité rapide : laissez Docker gérer ses règles (avec iptables-nft), et considérez Docker comme partie du système de pare-feu. Documentez ce qu’il possède.
- Si l’hôte est sensible en sécurité et que vous avez besoin d’une politique stricte : désactivez iptables de Docker seulement si vous avez le temps et l’expertise pour recréer le NAT/forwarding nécessaire en toute sécurité.
Comment « choisir un backend » sans drame
Votre objectif : un backend (nft) et un auteur (service nftables ou un gestionnaire unique).
La cause la plus courante de conflit n’est pas l’existence de nftables — c’est que quelque chose écrit encore des règles legacy ou les recharge à des moments étranges.
Basculer les alternatives iptables vers nft (si vous voulez le backend nft)
cr0x@server:~$ sudo update-alternatives --set iptables /usr/sbin/iptables-nft
update-alternatives: using /usr/sbin/iptables-nft to provide /usr/sbin/iptables (iptables) in manual mode
cr0x@server:~$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
update-alternatives: using /usr/sbin/ip6tables-nft to provide /usr/sbin/ip6tables (ip6tables) in manual mode
Décision : Après cela, tout outil basé sur iptables devrait écrire des règles nft via la couche de compat, pas legacy.
Si vous voyez encore de la divergence, quelque chose appelle explicitement iptables-legacy.
Rendre la politique nftables persistante (et explicite)
Un fichier nftables minimal et explicite vaut mieux qu’un fichier astucieux. Les pare-feux astucieux sont la cause des règles « temporaires » qui durent deux ans.
Debian charge typiquement /etc/nftables.conf si le service nftables est activé.
Aussi : si vous migrez depuis des scripts iptables, n’essayez pas de tout traduire mécaniquement le premier jour. Commencez par :
accept established/related, accept loopback, ports inbound requis, et la politique outbound requise. Puis étendez.
Blague n°2
Mélanger iptables-legacy et nftables, c’est comme faire tourner deux systèmes de paie : vous paierez tout le monde, juste pas toujours le bon montant.
Erreurs courantes : symptômes → cause racine → correction
1) « iptables -L semble correct, mais le trafic est toujours bloqué »
Symptômes : Le port apparaît autorisé dans la sortie iptables ; les clients expirent ; les compteurs nft montrent des drops ou des règles inattendues.
Cause racine : iptables utilise un backend (souvent legacy), tandis que les règles effectives sont dans nftables (ou l’inverse). Ou vous inspectez la mauvaise famille (ip vs inet).
Correction : Vérifiez les alternatives pour iptables/ip6tables. Dumpez nft list ruleset. Standardisez sur iptables-nft ou nft-only. Supprimez l’usage legacy et arrêtez les gestionnaires dupliqués.
2) « nft list ruleset est vide après reboot »
Symptômes : Des règles existent juste après application, puis disparaissent au reboot ; nftables.service inactif/désactivé.
Cause racine : Vous avez chargé les règles manuellement (interactive nft) mais ne les avez pas persistées, ou nftables.service est désactivé, ou un gestionnaire a écrasé les règles après le boot.
Correction : Activez le service nftables et assurez-vous que /etc/nftables.conf est correct. Auditez les services post‑boot comme Docker/UFW/firewalld pour leur comportement de reload.
3) « Le réseau Docker a cassé quand nous avons ‘simplifié’ le pare-feu »
Symptômes : Les conteneurs ne peuvent plus atteindre l’extérieur ou n’acceptent plus d’entrants ; connectivité aléatoire selon le cycle de vie du nœud.
Cause racine : Désactivation de l’intégration iptables de Docker sans remplacer équivalemment les règles NAT/forwarding/bridge dans nftables.
Correction : Réactivez iptables pour Docker jusqu’à ce que vous ayez une politique nftables testée pour le réseau conteneur. Validez le comportement de la chaîne FORWARD, le masquerade NAT, et l’état conntrack.
4) « IPv4 fonctionne, IPv6 est grand ouvert (ou complètement mort) »
Symptômes : Les scans de sécurité montrent une exposition IPv6 inattendue ; ou les clients IPv6 échouent tandis que IPv4 marche.
Cause racine : Vous avez configuré seulement iptables (v4) et oublié ip6tables/family inet ; ou les backends diffèrent entre IPv4 et IPv6.
Correction : Utilisez nft table inet pour une politique unifiée. Alignez les alternatives pour iptables et ip6tables. Décidez d’une posture IPv6 explicite.
5) « Des règles existent mais ne matchent jamais »
Symptômes : Les règles d’accept montrent zéro compteur ; tcpdump voit le trafic ; les clients échouent quand même.
Cause racine : Mismatch de priorité/ hook de chaîne ; le trafic est traité dans un hook différent (ingress vs input), ou droppé plus tôt dans une chaîne de priorité plus élevée, ou vous filtrez sur la mauvaise interface (renommages, bonds, VLANs).
Correction : Listez les chaînes avec hooks et priorités. Consolidez les chaînes pour le même hook. Confirmez les noms d’interface et pensez à matcher par adresse/sous‑réseau quand approprié.
6) « Tout casse seulement après le démarrage de fail2ban »
Symptômes : La protection SSH contre la brute force fonctionne, mais des utilisateurs légitimes se font bloquer ; les règles du pare-feu gonflent avec le temps.
Cause racine : fail2ban écrit dans iptables pendant que vous gérez nftables (ou l’inverse) ; les bans persistent de façon incohérente ; le mismatch de backend cause des bans périmés ou inefficaces.
Correction : Configurez fail2ban pour utiliser des actions nftables lorsque nftables est le plan de contrôle choisi, ou isolez fail2ban au même backend de façon cohérente.
Listes de contrôle / plan pas à pas
Checklist A : Standardiser un hôte Debian 13 sur nftables sans surprises
- Inventoriez les écrivains : Docker, Kubernetes, UFW, firewalld, fail2ban.
- Choisissez le propriétaire : nftables natif (recommandé) ou un gestionnaire unique.
- Alignez les alternatives iptables/ip6tables vers nft :
update-alternatives --set iptables /usr/sbin/iptables-nftupdate-alternatives --set ip6tables /usr/sbin/ip6tables-nft
- Activez le service nftables et assurez-vous que le fichier de configuration est la source de vérité unique.
- Appliquez la politique en fenêtre de maintenance ; gardez une console hors‑bande prête.
- Validez : ports entrants, connectivité sortante, flux conteneurs (si applicable), posture IPv6.
- Test de reboot. Toujours. Si vous ne testez pas le reboot, vous jouez à la roulette.
- Surveillez les compteurs et loguez les drops (avec parcimonie) pendant quelques jours.
Checklist B : Si vous devez garder des outils de type iptables
- Standardisez quand même sur iptables-nft sauf si vous avez un bloqueur avéré.
- Ne lancez pas nftables.service avec un fichier de politique séparé qui entre en conflit avec des règles gérées par iptables.
- Assurez‑vous que vos commandes d’inspection correspondent au backend :
- Backend iptables-nft : inspectez avec à la fois
iptables -L -vetnft list ruleset. - Backend legacy : inspectez explicitement avec
iptables-legacypour éviter l’auto‑tromperie.
- Backend iptables-nft : inspectez avec à la fois
- Documentez quel service charge les règles au boot (
iptables-persistent, scripts, unités systemd). - Vérifiez la compatibilité avec Docker/Kubernetes avant le rollout.
Checklist C : Réponse incident quand la propriété du pare-feu est floue
- Confirmez que le service écoute (
ss -lntp). - Confirmez que le trafic arrive (
tcpdumpsur l’interface). - Dump du ruleset nft et des règles iptables avec compteurs.
- Vérifiez les alternatives et recherchez la divergence des règles legacy.
- Vérifiez les logs pour des services rechargeant les règles après le boot.
- Arrêtez l’hémorragie : autorisez temporairement uniquement ce dont vous avez besoin dans le backend actif, puis planifiez un nettoyage.
- Après l’incident : supprimez les gestionnaires dupliqués et codifiez la propriété de la politique.
FAQ (questions réelles d’incidents réels)
1) nftables est‑il « meilleur » qu’iptables sur Debian 13 ?
Pour la plupart des usages serveur, oui : nftables est l’interface moderne, supporte les règles inet unifiées, et c’est la direction prise par l’écosystème.
Mais « meilleur » n’a pas d’importance si vos outils attendent la sémantique iptables ; alors le meilleur choix est celui que vous pouvez exploiter de manière cohérente.
2) Pourquoi iptables -L affiche des règles que je ne trouve pas dans mon fichier de config nft ?
Parce que ces règles peuvent être générées par un autre service (Docker, UFW, fail2ban), ou elles peuvent être la vue traduite iptables-nft de l’état nftables.
Le fichier de config n’est pas nécessairement l’origine ; c’est juste une source possible.
3) iptables et nftables peuvent‑ils coexister sans risque ?
Ils peuvent coexister si iptables utilise le backend nft (iptables-nft) et que vous le traitez comme une interface de compatibilité, pas comme un deuxième auteur.
Ils ne peuvent pas coexister sans risque si vous mélangez iptables-legacy avec une politique nftables sur le même hôte. C’est du split‑brain par conception.
4) Quelle est la manière la plus rapide de savoir si je suis en mode split‑brain ?
Comparez nft list ruleset avec iptables -L -v, puis vérifiez explicitement iptables-legacy -L.
Si legacy montre un monde différent de nft, vous avez trouvé votre fantôme.
5) Pourquoi mes règles d’accept ont‑elles des compteurs à zéro alors que des clients se connectent ?
Soit vous regardez au mauvais endroit (mauvaise table/famille/hook), soit le trafic est accepté plus tôt dans une autre chaîne,
soit il n’atteint pas ce hook (par exemple, trafic local output, forwarded, ou traité en ingress).
Les compteurs sont la vérité, mais seulement pour la règle que vous examinez réellement.
6) Dois‑je utiliser table inet ou des tables ip/ip6 séparées dans nftables ?
Utilisez table inet pour la plupart des politiques afin de ne pas diverger accidentellement le comportement IPv4 et IPv6.
Les tables séparées conviennent pour des cas avancés, mais elles augmentent le risque que l’IPv6 devienne « le problème de quelqu’un d’autre ».
7) Qu’en est‑il de UFW sur Debian 13 ?
UFW peut être opérationnellement correct si c’est l’autorité unique et que vous acceptez son modèle.
Le problème vient de le superposer à une politique nftables ou à un outillage conteneur qui écrit aussi des règles.
Choisissez un seul : pare-feu géré par UFW, ou pare-feu géré par nftables, pas les deux.
8) Comment migrer des règles iptables vers nftables ?
Ne faites pas d’abord une traduction 1:1. Commencez par une politique nftables minimale qui reproduit votre intention de sécurité,
puis ajoutez de la complexité. Validez avec des compteurs et des tests de trafic. Si vous devez garder des outils iptables temporairement,
standardisez sur iptables-nft et traitez la sortie nft comme l’état canonique.
9) Pourquoi un reboot a‑t‑il « changé » le pare‑feu ?
Parce qu’un service différent a chargé des règles au démarrage, ou un gestionnaire a appliqué sa propre politique après vos règles,
ou les noms d’interface ont changé et vos critères de correspondance ne s’appliquent plus. Le reboot est le grand sérum de vérité des configs.
10) Est‑il judicieux de logger les drops pendant le débogage ?
Oui, sélectivement. Loggez tout et vous allez vous faire un DoS disque et cerveau. Ajoutez des règles de log temporaires avec des limits de débit,
capturez suffisamment pour identifier le chemin, puis retirez‑les. Conservez les compteurs sur le long terme ; ils sont moins coûteux et souvent plus utiles.
Prochaines étapes à faire aujourd’hui
Si vous exploitez Debian 13 en production et que vous voulez que ce problème n’apparaisse plus à 3h du matin, faites ces trois choses :
- Décidez de la propriété. nftables-native, ou un seul gestionnaire. Pas de garde partagée.
- Prouvez la cohérence des backends. Alignez les alternatives iptables et ip6tables ; confirmez que vous n’utilisez pas accidentellement legacy d’un côté.
- Opérationnalisez l’inspection. Ajoutez un ensemble standard de commandes « vérité du pare-feu » à vos runbooks :
nft list ruleset,iptables -L -v,update-alternatives --display iptables, et destcpdumpciblés.
Puis faites la partie ennuyeuse : redémarrez un hôte canari et confirmez que les règles que vous pensez avoir sont bien celles que vous obtenez. C’est tout le jeu.