Vous avez installé Fail2ban. Vous avez activé un jail SSH. Vous avez même vu quelqu’un marteler le port 22 comme si c’était une banque. Et pourtant : personne n’est banni. Aucune entrée dans le pare-feu. Aucun compteur « banned » qui augmente. Juste le silence.
En production, le silence est rarement la paix. C’est souvent de la télémétrie manquante, un backend incorrect, la mauvaise famille de pare-feu ou un jail qui n’a jamais matché une ligne. La solution n’est pas « réinstaller Fail2ban » (c’est comme perdre une après-midi). La solution, c’est la vérification : prouver le chemin des données, prouver le match, prouver le ban et prouver que le ban est exécutable.
Playbook de diagnostic rapide
Si vous êtes de garde, commencez ici. C’est la séquence « trouver le goulot en cinq minutes ». Elle est assumée parce que l’alternative consiste à errer dans les fichiers de config pendant que les attaques continuent.
Première question : Fail2ban est-il actif et surveille-t-il le jail que vous pensez ?
- Vérifiez l’état du service et les erreurs récentes dans le journal.
- Listez les jails activés et confirmez que votre jail cible est présent.
Deuxième : voit-il les événements (logs) et les matche-t-il (filtres) ?
- Confirmez le backend (journal systemd vs fichiers de logs).
- Confirmez que la source de logs contient bien les lignes d’échec attendues.
- Exécutez un test regex contre des lignes de log connues.
Troisième : essaye-t-il de bannir, et les bans sont-ils appliqués ?
- Bannissez manuellement une IP de test et vérifiez si des règles de pare-feu apparaissent.
- Validez si vous êtes sur nftables ou iptables et que Fail2ban est configuré en conséquence.
- Validez l’action sélectionnée dans le jail et que la « famille » du pare-feu correspond à la réalité du système.
Le mode d’échec le plus courant sur les Ubuntu modernes n’est pas Fail2ban lui‑même. C’est un décalage entre l’endroit où les logs vivent (systemd-journald vs fichiers) et la couche de pare‑feu active (nftables vs iptables-legacy). Fail2ban ne peut pas bannir ce qu’il ne voit pas, et il ne peut pas bloquer ce qu’il ne sait pas programmer.
Modèle mental : événements → correspondances → bans → application
Fail2ban est simple comme un détecteur de fumée. Il écoute. Il reconnaît un motif. Il exécute une action. Si vous le mettez dans la mauvaise pièce, ou si les piles sont mortes, il « fonctionne » avec un calme impressionnant.
Pensez en quatre couches :
- Événements : les échecs d’authentification apparaissent quelque part (un fichier comme
/var/log/auth.logou le journal systemd). - Correspondances : le filtre d’un jail (regex) matche ces lignes d’événements et compte les échecs par IP sur une fenêtre temporelle.
- Bans : quand les seuils sont dépassés (findtime/maxretry), Fail2ban décide de bannir une IP.
- Application : l’action de ban insère des règles dans un pare‑feu (nftables ou iptables) ou indique à un service (comme une ACL d’application) de bloquer.
Quand Fail2ban « n’interdit rien », ne devinez pas quelle couche a échoué. Prouvez‑le. En pratique :
- Pas d’événements : mauvaise source de logs, permissions, ou le service log ailleurs (logs de conteneur, syslog désactivé, etc.).
- Événements mais pas de correspondances : mauvais filtre, mauvais jail, format de log différent, ou votre service ne produit pas les chaînes d’échec que le filtre attend.
- Correspondances mais pas de bans : seuils trop hauts, ignoreip couvre tout, paramètres temporels incorrects, ou le jail n’est pas activé.
- Bans mais pas d’application : mauvaise action, mauvais backend de pare‑feu, conflit avec un gestionnaire de pare‑feu, ou ordre des règles qui fait que votre « blocage » ne bloque jamais.
Idée paraphrasée (Gene Kim) : « La fiabilité vient d’un retour rapide et de petits changements réversibles. » C’est l’objet de ce workflow : des boucles de rétroaction serrées qui vous évitent de deviner.
Faits intéressants et contexte (rapide, utile, parfois geek)
- Fail2ban est antérieur à l’ère cloud. Il a démarré au début des années 2000, quand les bruteforces SSH et le password spraying FTP étaient du bruit de fond quotidien sur Internet.
- Il ne « détecte » pas des attaquants. Il détecte des motifs dans les logs. Si un attaquant évite de générer les logs que vous attendez (ou frappe un endpoint que vous ne surveillez pas), Fail2ban restera poliment ignorant.
- La cible par défaut originale était iptables. L’écosystème a lentement migré vers nftables ; aujourd’hui, les pare‑feux Linux tournent souvent via nftables même quand vous tapez « iptables ».
- systemd-journald a changé la donne des logs. Sur certaines installations,
/var/log/auth.logest présent ; sur d’autres, le journal est la source canonique. Fail2ban peut lire l’un ou l’autre, mais vous devez choisir correctement. - « iptables » peut signifier plusieurs choses. Il y a iptables-legacy et iptables-nft. Le nom de la commande est le même, le backend diffère, et les règles peuvent atterrir là où vous ne regardez pas.
- UFW est une couche de politique. Historiquement il utilisait iptables ; sur les systèmes plus récents il peut s’intégrer à nftables. Fail2ban peut coexister, mais l’ordre importe.
- IPv6 est le piège discret. Si votre service est accessible via IPv6 et que vous ne bannissez que l’IPv4, votre « ban » n’est qu’un ralentissement, pas un blocage.
- Les résolutions DNS inverses peuvent retarder les bans. Si vous activez des fonctions qui provoquent des opérations DNS lentes dans la chaîne de ban, vous pouvez obtenir des comportements étranges (« il bannit des heures plus tard »).
Blague #1 : Fail2ban ne « ne marche pas ». Il fonctionne exactement comme configuré, ce qui est une phrase beaucoup moins réconfortante à 03:00.
Workflow de vérification : tâches pratiques avec commandes, sens, décisions
Ceci est le cœur de l’article : vérifications réelles, dans un ordre sensé, avec « ce que ça signifie » et « ce que vous faites ensuite ». Exécutez-les sur l’hôte où Fail2ban est installé.
Task 1 — Confirmer que Fail2ban tourne réellement (et ne plante pas)
cr0x@server:~$ systemctl status fail2ban --no-pager
● fail2ban.service - Fail2Ban Service
Loaded: loaded (/usr/lib/systemd/system/fail2ban.service; enabled; preset: enabled)
Active: active (running) since Sun 2025-12-28 09:12:19 UTC; 1h 7min ago
Docs: man:fail2ban(1)
Main PID: 1247 (fail2ban-server)
Tasks: 5 (limit: 19020)
Memory: 39.8M
CPU: 1.421s
CGroup: /system.slice/fail2ban.service
└─1247 /usr/bin/python3 /usr/bin/fail2ban-server -xf start
Ce que ça signifie : « active (running) » est le minimum requis. S’il est « failed » ou en redémarrage, les bans ne tiendront pas et les jails peuvent ne jamais se charger.
Décision : S’il n’est pas stable, allez directement à la Task 2 (erreurs du journal) avant de toucher la configuration.
Task 2 — Lire les dernières erreurs/avertissements de Fail2ban
cr0x@server:~$ journalctl -u fail2ban -n 200 --no-pager
Dec 28 09:12:19 server fail2ban-server[1247]: Server ready
Dec 28 10:01:07 server fail2ban-server[1247]: WARNING Found no accessible config files for 'filter.d/sshd'. Skipping...
Dec 28 10:01:07 server fail2ban-server[1247]: ERROR Unable to read the filter 'sshd'
Ce que ça signifie : C’est Fail2ban qui vous dit qu’il ne peut pas charger un filtre, ouvrir un log, parler au pare‑feu ou lier son socket. Croyez‑le.
Décision : Corrigez d’abord le fichier/permission indiqué. Ne « tunez le bantime » alors qu’il ne peut pas charger le jail.
Task 3 — Lister les jails en cours (ceux que Fail2ban a réellement chargés)
cr0x@server:~$ sudo fail2ban-client status
Status
|- Number of jail: 2
`- Jail list: sshd, nginx-http-auth
Ce que ça signifie : Si votre jail attendu n’est pas listé, il n’est pas en cours. Fin de l’histoire.
Décision : Si un jail manque, validez la config à la Task 4 et vérifiez l’activation dans le fichier de jail. Pas de jail, pas de ban.
Task 4 — Valider l’analyse de la configuration sans lancer de concours de conjectures
cr0x@server:~$ sudo fail2ban-client -d
...snip...
Jail sshd: backend = systemd
Jail sshd: enabled = true
Jail sshd: maxretry = 5
Jail sshd: findtime = 600
Jail sshd: bantime = 3600
Jail sshd: action = nftables[type=multiport]
...snip...
Ce que ça signifie : -d affiche la configuration calculée après les inclusions. C’est ici que vous attrapez « j’ai modifié jail.conf mais jail.local le remplace » et autres classiques.
Décision : Si le backend/l’action/les chemins ne sont pas ceux attendus, arrêtez‑vous et corrigez les overrides. Ne déboguez pas la mauvaise réalité.
Task 5 — Inspecter le statut d’un jail spécifique (c’est votre tableau de bord)
cr0x@server:~$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 1
| |- Total failed: 44
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
Ce que ça signifie : « Total failed » qui augmente signifie qu’il lit les logs et matche. « Total banned » qui reste à zéro signifie que les seuils ne sont pas atteints, que ignoreip attrape tout ou que l’action échoue.
Décision : Si « File list » pointe vers un fichier que vous n’avez pas ou n’utilisez pas (commun sur les systèmes basés sur le journal), passez aux Tasks 6–8.
Task 6 — Confirmer où les échecs d’authentification sont consignés sur Ubuntu 24.04
cr0x@server:~$ ls -l /var/log/auth.log
-rw-r----- 1 syslog adm 148322 Dec 28 10:18 /var/log/auth.log
Ce que ça signifie : Si /var/log/auth.log existe et se met à jour, le backend fichier peut fonctionner. S’il est absent ou obsolète, vous devez probablement utiliser le backend systemd.
Décision : Si absent/obsolète, utilisez la Task 7 pour confirmer que le journal contient les événements puis configurez backend = systemd pour le jail.
Task 7 — Prouver que les échecs existent dans le journal
cr0x@server:~$ sudo journalctl -u ssh --since "30 min ago" --no-pager | tail -n 20
Dec 28 10:09:41 server sshd[3188]: Failed password for invalid user admin from 203.0.113.90 port 49152 ssh2
Dec 28 10:09:44 server sshd[3188]: Failed password for root from 203.0.113.90 port 49153 ssh2
Ce que ça signifie : Le système a les preuves dont Fail2ban a besoin. Maintenant, il faut s’assurer que le jail lit la même source.
Décision : Si le journal a des entrées mais que le « File list » du jail montre /var/log/auth.log, passez à backend = systemd (et retirez les overrides de logpath trompeurs).
Task 8 — Vérifier le backend effectif et le logpath du jail
cr0x@server:~$ sudo fail2ban-client get sshd backend
systemd
cr0x@server:~$ sudo fail2ban-client get sshd logpath
/var/log/auth.log
Ce que ça signifie : Oui, vous pouvez vous retrouver avec un backend systemd et un logpath obsolète toujours configuré (surtout si vous avez copié des extraits plus anciens). C’est confus et inutile.
Décision : Si vous utilisez le backend systemd, supprimez logpath de ce jail sauf raison spécifique. Gardez la configuration ennuyeuse et claire.
Task 9 — Vérifier que Fail2ban peut lire la source de logs (permissions et groupes)
cr0x@server:~$ ps -o user,group,comm -p $(pgrep -xo fail2ban-server)
USER GROUP COMMAND
root root fail2ban-server
cr0x@server:~$ sudo -u root test -r /var/log/auth.log && echo "readable"
readable
Ce que ça signifie : Sur Ubuntu, Fail2ban tourne généralement en root, donc les permissions de fichier sont rarement le blocage. Mais si vous le durcissez pour le faire tourner sans privilèges, l’accès aux logs devient réel.
Décision : Si vous exécutez Fail2ban en non‑root, assurez‑vous qu’il peut lire les logs et manipuler le pare‑feu. Sinon, il ne pourra pas.
Task 10 — Exécuter un test regex du filtre sur des données réelles (arrêtez d’espérer)
cr0x@server:~$ sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf --print-all-matched
Running tests
=============
Use failregex filter file : sshd, basedir: /etc/fail2ban
Use log file : /var/log/auth.log
Results
=======
Failregex: 12 total
|- #) [# of hits] regular expression
| 1) [12] Failed password for .* from <HOST>
Ignoreregex: 0 total
Summary
=======
Lines: 1828 lines, 0 ignored, 12 matched, 1816 missed
Ce que ça signifie : Si ceci indique « 0 matched », Fail2ban ne peut pas bannir à partir de cette combinaison filtre/log. Vos logs peuvent être dans le journal, ou les messages SSHD sont différents (modules PAM, localisation, etc.).
Décision : Corrigez la capacité de correspondance avant de toucher aux seuils. Si ça ne matche pas, la valeur de maxretry est sans objet.
Task 11 — Confirmer que la logique de fenêtre temporelle n’empêche pas les bans
cr0x@server:~$ sudo fail2ban-client get sshd findtime
600
cr0x@server:~$ sudo fail2ban-client get sshd maxretry
5
cr0x@server:~$ sudo fail2ban-client get sshd bantime
3600
Ce que ça signifie : Vous bannissez quand une IP produit maxretry matches dans findtime. Si les attaquants répartissent les tentatives dans le temps ou sur des noms d’utilisateur différents avec des lignes de log différentes, vous n’atteindrez peut‑être pas le seuil.
Décision : Si « Total failed » augmente mais pas de bans, réduisez temporairement maxretry à 2 et gardez findtime raisonnable (par ex. 10 minutes). Vérifiez que les bans se produisent, puis réajustez.
Task 12 — Vérifier les règles d’ignore (la couverture d’immunité silencieuse)
cr0x@server:~$ sudo fail2ban-client get sshd ignoreip
127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16
Ce que ça signifie : Si votre trafic provient d’un VPN ou d’un NAT inclus dans ignoreip, Fail2ban ne fera rien. C’est une fonctionnalité et aussi un générateur d’incidents.
Décision : Gardez les listes d’ignoreip étroites. Ajoutez vos IP d’administration, pas tout l’espace d’adresses de l’entreprise, sauf si vous aimez expliquer pourquoi des portables compromis peuvent bruteforcer librement.
Task 13 — Forcer un ban (test contrôlé) pour vérifier la couche action
cr0x@server:~$ sudo fail2ban-client set sshd banip 203.0.113.90
1
cr0x@server:~$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 44
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list: 203.0.113.90
Ce que ça signifie : Cela prouve que le plan de contrôle de Fail2ban peut émettre des bans. Cela ne prouve pas que le pare‑feu l’applique. C’est la suite.
Décision : Si le ban apparaît ici, passez à la validation du pare‑feu. S’il n’apparaît pas, votre jail/action est cassé à l’intérieur de Fail2ban (ou vous avez utilisé le mauvais nom de jail).
Task 14 — Identifier si le système utilise nftables ou iptables pour l’application
cr0x@server:~$ sudo 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
/usr/sbin/iptables-nft - priority 20
/usr/sbin/iptables-legacy - priority 10
Ce que ça signifie : Si iptables pointe vers iptables-nft, alors les « règles iptables » peuvent en réalité être des structures nftables sous‑jacentes. Si vous utilisez une action nftables de Fail2ban, inspectez nftables directement.
Décision : Choisissez un chemin d’application et observez‑le avec les bons outils. Ne mélangez pas iptables-legacy avec nftables à moins de vouloir gérer deux univers parallèles.
Task 15 — Vérifier que nftables contient une table/chaîne Fail2ban (si actions nftables)
cr0x@server:~$ sudo nft list ruleset | sed -n '1,120p'
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
ct state established,related accept
iif "lo" accept
tcp dport 22 accept
}
}
table inet f2b-table {
set f2b-sshd {
type ipv4_addr
elements = { 203.0.113.90 }
}
chain f2b-sshd {
ip saddr @f2b-sshd drop
return
}
}
Ce que ça signifie : Vous devez voir une table/chaîne ou un set f2b contenant votre IP bannie. Si c’est présent, Fail2ban a programmé nftables.
Décision : Si le set/chaîne existe mais le trafic passe encore, vous avez probablement un problème d’ordre des règles (la chaîne Fail2ban n’est pas branchée assez tôt), ou votre service est accessible via IPv6 alors que vous n’avez banni que l’IPv4.
Task 16 — Vérifier qu’iptables contient des chaînes Fail2ban (si actions iptables)
cr0x@server:~$ sudo iptables -S | sed -n '1,80p'
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N f2b-sshd
-A INPUT -p tcp -m tcp --dport 22 -j f2b-sshd
-A f2b-sshd -s 203.0.113.90/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -j RETURN
Ce que ça signifie : La présence de la chaîne f2b-sshd et d’un jump depuis INPUT vers elle est la preuve de la configuration d’application.
Décision : Si vous avez une chaîne mais pas de jump vers elle, l’action n’a créé que la chaîne sans l’attacher. C’est un problème de configuration d’action.
Task 17 — Vérifier que le ban bloque réellement les paquets (ne faites pas confiance à la config)
cr0x@server:~$ sudo timeout 5 tcpdump -ni any 'host 203.0.113.90 and tcp port 22'
tcpdump: data link type LINUX_SLL2
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
10:21:02.112345 IP 203.0.113.90.49160 > 198.51.100.10.22: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0
Ce que ça signifie : Vous voyez des SYN arriver. Vérifiez ensuite si le serveur répond (SYN-ACK) ou s’il drop/reject. Si votre ban est « drop », vous devriez voir des SYN entrants sans réponses.
Décision : Si vous voyez encore des SYN-ACK sortants, votre règle de pare‑feu n’est pas atteinte (mauvaise chaîne/ordre/famille d’interface), ou le service est lié différemment que vous le pensez.
Task 18 — Débannir votre IP de test et nettoyer
cr0x@server:~$ sudo fail2ban-client set sshd unbanip 203.0.113.90
1
Ce que ça signifie : Vous n’essayez pas de bannir définitivement des IP de documentation (ou le Wi‑Fi de votre collègue). Vous vérifiez la chaîne.
Décision : Si l’unban ne supprime pas l’état dans le pare‑feu, le nettoyage d’action est cassé, ou vous regardez le mauvais backend de pare‑feu.
Réalité du pare-feu sur Ubuntu 24.04 : nftables, iptables et ce que Fail2ban touche réellement
Ubuntu 24.04 se situe dans l’époque où nftables est la vérité sous‑jacente, même quand votre mémoire musculaire tape encore iptables. Fail2ban peut utiliser l’un ou l’autre, mais vous devez vous aligner :
- Actions nftables créent des tables/chaînes/sets nft directement. Vous validez avec
nft list ruleset. - Actions iptables insèrent des règles iptables. Sur les systèmes avec iptables‑nft, ces règles peuvent être traduites en structures nftables, mais vous les gérez toujours via les outils iptables.
Choisissez une interface d’application et observez‑la correctement
Si vous configurez Fail2ban pour utiliser des actions nftables, ne validez pas les bans avec iptables -S puis ne déclarez pas que c’est cassé. C’est comme vérifier le niveau d’huile en regardant les pneus. Techniquement tout fait partie de la voiture, mais vous ne mesurez pas la bonne chose.
UFW complique mais n’interdit pas Fail2ban
UFW est un gestionnaire de politiques, pas un moteur de pare‑feu. L’action iptables classique de Fail2ban coexiste souvent avec UFW parce qu’UFW laisse de la place pour des chaînes supplémentaires. Mais UFW peut aussi appliquer des politiques strictes et ordonner ses chaînes avant ou après celles de Fail2ban selon l’intégration.
Règle opérationnelle : si vous utilisez UFW, assurez‑vous que le blocage de Fail2ban est évalué tôt dans le chemin d’entrée pour les ports ciblés. Si vous ne savez pas, testez avec la Task 17 et arrêtez de théoriser.
IPv6 : le coupable qui continue de se connecter malgré le ban
Si votre service écoute sur :: (wildcard IPv6) et que le client a une connectivité IPv6, un ban IPv4 ne touchera pas cette connexion. Cela peut ressembler à « Fail2ban n’interdit pas » alors qu’il le fait, mais sur la mauvaise famille de protocoles.
Approche pratique : confirmez quelle famille d’adresses les clients utilisent et configurez des actions Fail2ban couvrant IPv4 et IPv6 quand c’est approprié.
Filtres et regex : quand Fail2ban « fonctionne » mais ne matche jamais
Les filtres sont l’endroit où vos hypothèses viennent mourir. Fail2ban ne comprend pas « une attaque ». Il comprend « une ligne de log qui correspond à cette regex ». C’est à la fois sa force et son piège.
Connaissez votre format de log : OpenSSH n’est pas la seule voix dans auth
Entre PAM, différents réglages SSHD et parfois des patchs personnalisés, les chaînes d’échec peuvent varier. Certains environnements émettent « Invalid user », d’autres « Failed password », d’autres des champs différents pour les échecs publickey. Votre filtre doit matcher votre réalité.
Utilisez fail2ban-regex comme barrière, pas comme réflexion après coup
Si vous ne faites qu’une chose avec discipline : exécutez fail2ban-regex contre la source de log exacte que vous avez configurée. S’il ne matche pas, vous n’avez pas un problème de ban. Vous avez un problème de pattern.
Les backends journald changent la façon de cibler
En utilisant backend = systemd, Fail2ban utilise des requêtes journal plutôt que de suivre un fichier. C’est généralement mieux sur les systèmes modernes, mais cela signifie que l’ancienne sagesse du « logpath » peut vous induire en erreur. Dans le monde du journal, la question devient : le nom d’unité est‑il correct (ex. ssh vs sshd) et vos permissions journal sont‑elles suffisantes ?
Blague #2 : Regex est un langage en écriture seule — jusqu’à ce que le rapport d’incident vous demande de le relire.
Actions : quand ça matche, mais rien n’est bloqué
Une fois que vous avez prouvé les correspondances, la classe d’échec suivante est « Fail2ban a décidé de bannir, mais l’application n’a rien fait ». Cela tombe généralement dans l’un de ces cas :
- Mauvaise famille de pare‑feu : vous avez utilisé une action iptables sur un système où vous n’inspectez que nftables, ou l’inverse.
- Ordre des règles : la règle de ban existe mais n’est jamais atteinte parce que des règles antérieures acceptent le trafic (commun avec des règles ACCEPT trop larges, ou des hooks d’entrée qui contournent la chaîne).
- Mauvaise interface : votre service est sur un port/protocole différent de ce que l’action suppose, ou vous bannissez le port 22 alors que SSH écoute sur 2222.
- Mauvais couple IPv6 : vous avez banni IPv4 mais le client se connecte via IPv6.
- Permissions/capacités : Fail2ban ne peut pas programmer le pare‑feu à cause d’un durcissement ou d’une politique système.
Le ban/unban manuel est votre meilleur « test unitaire »
Dans les systèmes réels, vous pouvez passer des heures à attendre qu’un seuil déclenche un ban. Ne le faites pas. Utilisez la Task 13 pour forcer un ban puis inspectez l’état du pare‑feu. Si le ban manuel ne crée pas d’entrées de pare‑feu, vous avez un problème d’exécution d’action. S’il le fait mais que les bans automatiques ne se produisent pas, vous avez un problème d’événement/correspondance/seuil.
Vérifiez l’attachement de la chaîne, pas seulement son existence
Il est possible d’avoir une belle chaîne Fail2ban peuplée que rien n’appelle jamais. C’est l’équivalent firewall de construire un poste de garde dans le parking et de ne jamais y mettre de gardien.
Pour iptables, il faut voir un jump depuis INPUT (ou la chaîne pertinente) vers f2b-*. Pour nftables, il faut que la chaîne f2b soit référencée dans le hook correct, ou qu’un set soit utilisé par une règle qui s’exécute réellement pour le trafic entrant.
Trois mini-histoires d’entreprise issues des tranchées sans bans
1) L’incident causé par une mauvaise hypothèse
L’équipe avait une petite flotte de serveurs Ubuntu mise à jour vers une nouvelle version. La checklist de migration incluait « installer Fail2ban » et « activer le jail sshd », et quelqu’un a coché la case. Quelques jours plus tard, leurs logs d’authentification montraient un pattern de bruteforce soutenu : des milliers d’échecs, réguliers comme un métronome.
Tout le monde supposait que le système de ban couvrait le problème parce que ça l’avait toujours fait. L’ingénieur d’astreinte a regardé fail2ban-client status et a vu le jail sshd « running ». Rassurant. Ils sont revenus à d’autres tâches.
Le lendemain matin, quelqu’un a remarqué des pics CPU corrélés aux rafales d’authentification. Les pics n’étaient pas catastrophiques, mais suffisants pour dégrader un service sensible à la latence partageant la même VM. Quand ils ont finalement consulté les détails du jail, « Total failed » montait et « Total banned » restait bloqué à zéro.
La mauvaise hypothèse : « Si le jail est en cours, il doit bannir. » En réalité, le jail lisait /var/log/auth.log, qui existait mais était obsolète parce que les événements d’auth du système étaient désormais dans journald uniquement. Pas d’entrée live. Pas de ban.
La correction a été ennuyeuse et rapide : passer le jail à backend = systemd, supprimer l’override logpath qui le fixait sur le fichier obsolète, puis forcer le ban d’une IP de test pour valider les règles nftables. Une fois la chaîne visible et effective, le bruit du bruteforce a chuté immédiatement. Le postmortem a été court et légèrement embarrassant, ce qui est la meilleure sorte.
2) L’optimisation qui a mal tourné
Un ingénieur soucieux de sécurité voulait réduire les écritures disque et le volume de logs. Il a resserré la configuration rsyslog et s’est davantage appuyé sur journald. Ce n’est pas mauvais en soi. Mais il a aussi ajusté la rotation et la rétention de manière à faire disparaître certains logs basés fichiers. Personne n’a remarqué parce que les services fonctionnaient toujours et que le journal contenait encore les données.
Fail2ban, en revanche, était toujours configuré avec des backends fichiers pointant vers des chemins qui n’existaient plus. Comme Fail2ban ne plantait pas, l’hypothèse est devenue « c’est OK ». Il démarrait, tournait, rapportait même des jails. Mais il suivait de l’air vide.
Puis est survenue la partie subtile : ils avaient aussi augmenté drastiquement findtime et bantime pour « être plus durs ». L’intention était bonne — bannir plus longtemps. L’effet a été pire : quand ils ont réactivé la journalisation, Fail2ban avait désormais une fenêtre plus large pour évaluer, mais le filtre regex a matché des lignes bénignes additionnelles à cause d’un format PAM personnalisé. Il a commencé à bannir des IPs de sortie NAT internes pendant une fenêtre de maintenance.
Les opérations ont vu un problème réseau intermittent. Les développeurs ont vu « SSH cassé ». La sécurité a cru à une attaque. La vérité : une optimisation des logs plus un tuning agressif des bans ont amplifié un mauvais match de filtre.
La récupération a été disciplinée : revenir à un ensemble minimal de filtres connus bons, passer les backends à journald explicitement, réduire les seuils à des valeurs raisonnables, et restreindre ignoreip aux plages admin effectives. Ils ont gardé journald comme stockage principal, mais ont arrêté de prétendre que des logs invisibles pouvaient être parsés par des outils qui s’attendent à des fichiers.
3) La pratique ennuyeuse mais correcte qui a sauvé la mise
Une autre organisation exécutait un job standardisé de « vérification des contrôles de sécurité » après chaque cycle de patch OS. Ce n’était pas élégant ; c’était une poignée de commandes capturées dans un runbook avec des sorties attendues. Une de ces vérifications forçait un ban temporaire sur une IP de test et validait qu’une règle de pare‑feu apparaissait dans le bon sous‑système.
Pendant un déploiement routinier, une nouvelle image de base a changé l’alternative iptables de legacy à nft. Rien d’autre dans la pile applicative n’a cassé. Le déploiement semblait propre. Mais le job de vérification a échoué : le ban test apparaissait dans le statut de Fail2ban, pourtant la chaîne iptables attendue n’était pas présente. Pas de règles correspondantes.
Parce que le test était routinier, cela a été remarqué immédiatement. L’équipe n’a pas attendu qu’un attaquant prouve la faille. Ils ont simplement mis à jour l’action Fail2ban vers nftables et ajusté la validation pour inspecter nft list ruleset au lieu de greper la sortie iptables. Dix minutes plus tard, le pipeline passait. Ils ont poussé la nouvelle baseline et sont passés à autre chose.
Le meilleur : personne n’a dû débattre en réunion pour savoir si les bans « fonctionnaient probablement encore ». Ils avaient des preuves. La pratique ennuyeuse et correcte ne gagne pas de prix, mais elle garde vos nuits calmes.
Erreurs courantes : symptôme → cause racine → correction
1) Symptom : le jail est listé, mais « Total failed » reste à 0
Cause racine : Mauvaise source de logs. Vous taillez un fichier qui n’est pas écrit, ou l’unité que vous interrogez dans journald est incorrecte.
Correction : Prouvez que des échecs existent (Task 7) et alignez backend/logpath (Tasks 6–8). Ne devinez pas. Faites lire au jail ce que votre système écrit.
2) Symptom : « Total failed » augmente, mais « Total banned » reste à 0 éternellement
Cause racine : Seuils trop élevés, ignoreip inclut la plage source de l’attaquant, ou vos échecs sont répartis dans le temps au‑delà de findtime.
Correction : Vérifiez les seuils et ignoreip (Tasks 11–12). Réduisez temporairement maxretry pour valider la chaîne de ban, puis réajustez.
3) Symptom : « Currently banned » affiche des IPs, mais les attaquants se connectent toujours
Cause racine : Mismatch d’application : mauvaise action (iptables vs nftables), ordre des règles, ou contournement IPv6.
Correction : Force‑bannez une IP de test (Task 13), puis vérifiez dans le sous‑système de pare‑feu correct (Tasks 14–16) et validez le comportement des paquets (Task 17). Ajoutez la couverture IPv6 si nécessaire.
4) Symptom : les logs de Fail2ban affichent « No such file or directory » pour logpath
Cause racine : Extraits de jail anciens pointant vers /var/log/auth.log ou des logs d’app qui n’existent plus parce que la journalisation a été déplacée vers journald ou stdout de conteneur.
Correction : Passez à backend = systemd quand c’est pertinent, ou assurez‑vous que le service journalise dans un fichier lisible et correctement roté.
5) Symptom : le ban manuel fonctionne, les bans automatiques n’arrivent jamais
Cause racine : Mismatch de filtre : votre regex ne matche pas les lignes d’échec réelles. Ou le jail surveille le mauvais port/nom de service.
Correction : Exécutez fail2ban-regex (Task 10) sur la source réelle et ajustez le filtre ou les paramètres du jail jusqu’à obtenir des correspondances.
6) Symptom : après activation de UFW, les bans cessent de fonctionner
Cause racine : L’ordre des chaînes a changé ; les règles UFW acceptent le trafic avant que Fail2ban ait la chance de le dropper.
Correction : Assurez‑vous que les règles Fail2ban sont évaluées tôt pour les ports ciblés. Validez par tests de comportement (Task 17), pas seulement par présence de règle.
7) Symptom : Fail2ban bannit vos collègues pendant un déploiement
Cause racine : NAT : beaucoup de personnes partagent une IP d’egress, et les échecs de plusieurs hôtes s’accumulent sur cette adresse.
Correction : Ajoutez les adresses NAT de l’entreprise appropriées à ignoreip (de façon ciblée), ou augmentez maxretry/findtime pour éviter de punir un egress partagé. Envisagez aussi de mettre l’accès admin derrière un VPN avec identité par utilisateur.
8) Symptom : le service Fail2ban démarre, mais les jails ne se chargent pas après une modification
Cause racine : Erreur de syntaxe dans un fichier de jail ou problème d’ordre d’inclusion. Fail2ban est strict, et une seule mauvaise strophe peut désactiver ce que vous pensiez activé.
Correction : Utilisez fail2ban-client -d (Task 4) et les erreurs du journal (Task 2) pour identifier le fichier fautif. Corrigez, redémarrez et revérifiez la liste des jails.
Checklists / plan pas à pas
Checklist A — « J’ai besoin que les bans marchent aujourd’hui » (30–60 minutes, discipline)
- Confirmer la santé de Fail2ban :
systemctl status fail2ban(Task 1). - Lire les erreurs Fail2ban :
journalctl -u fail2ban(Task 2). - Vérifier que votre jail tourne :
fail2ban-client status(Task 3). - Inspecter les détails du jail :
fail2ban-client status sshd(Task 5). - Prouver que des échecs existent dans la source de logs choisie (Tasks 6–7).
- Prouver que le filtre matche :
fail2ban-regex(Task 10). - Forcer le ban d’une IP de test :
fail2ban-client set sshd banip ...(Task 13). - Vérifier l’état du pare‑feu avec le bon outil (Tasks 14–16).
- Valider le comportement avec tcpdump (Task 17), puis débannir (Task 18).
Checklist B — Durcir sans casser les bans (parce que « sécurisé » n’est pas « non fonctionnel »)
- Choisir votre backend d’application : nftables ou iptables‑nft. Documentez‑le.
- Standardiser les jails dans
/etc/fail2ban/jail.d/*.localplutôt que d’éditerjail.conf. - Privilégier
backend = systemdsur les hôtes où journald est la source autoritaire. - Garder
ignoreipminimal ; traitez‑le comme des allowlists de pare‑feu (revues, justifiées, limitées). - Couvrir IPv6 si vos services sont joignables via IPv6.
- Ajouter un simple test de vérification de ban à vos checks post‑déploiement (ban manuel, inspecter le pare‑feu, unban).
Checklist C — Quand vous suspectez des problèmes d’ordre des règles
- Forcer un ban d’IP de test (Task 13).
- Trouver la présence de règle et de chaîne (Tasks 15–16).
- Confirmer que la chaîne de ban est réellement référencée depuis le chemin d’entrée (iptables : jump depuis INPUT ; nft : hook de chaîne ou set référencé).
- Tester le comportement avec tcpdump (Task 17).
- Ajuster la configuration d’action ou l’ordre des politiques de pare‑feu jusqu’à ce que les paquets cessent d’être acceptés.
FAQ
1) Pourquoi Fail2ban montre « Total failed » qui augmente mais n’interdit toujours pas ?
Parce que le bannissement dépend d’un seuil. Vérifiez maxretry, findtime et ignoreip. Réduisez temporairement maxretry pour prouver que la chaîne fonctionne, puis ajustez.
2) Dois‑je utiliser backend = systemd sur Ubuntu 24.04 ?
Si vos échecs d’authentification vivent dans journald (cas fréquent), oui. Utilisez le journal comme source de vérité. Le tailing de fichier est acceptable quand le fichier est réel, à jour et formaté de façon cohérente.
3) Comment savoir si j’utilise nftables ou iptables ?
Vérifiez update-alternatives --display iptables et inspectez les règles actives avec l’outil correspondant. Si Fail2ban utilise des actions nftables, inspectez avec nft list ruleset.
4) Je vois des bans dans le statut Fail2ban. Est‑ce que ça garantit que le trafic est bloqué ?
Non. Cela ne prouve que l’état interne de Fail2ban. Validez toujours l’application en vérifiant les règles du pare‑feu et le comportement des paquets (tcpdump ou tentative de connexion contrôlée).
5) Pourquoi le ban manuel marche mais l’automatique non ?
Le ban manuel passe outre le filtrage. Les bans automatiques dépendent du match des lignes de log. Utilisez fail2ban-regex sur la source exacte pour prouver que votre filtre matche la réalité.
6) UFW peut‑il interférer avec Fail2ban ?
Oui, généralement via l’ordre des règles ou des hypothèses de politique conflictuelles. La solution n’est pas « désactiver UFW ». La solution est de s’assurer que le blocage de Fail2ban est évalué pour le chemin de trafic pertinent et de vérifier le comportement.
7) Pourquoi suis‑je parfois banni de mon propre serveur ?
NAT et egress partagé. Plusieurs personnes échouent des connexions depuis la même IP publique ; les échecs s’accumulent sur cette adresse. Ajoutez vos IP d’egress admin à ignoreip de façon ciblée, ou améliorez les patterns d’accès (VPN, bastion, clés).
8) Dois‑je me préoccuper d’IPv6 avec Fail2ban ?
Si le service est accessible via IPv6, oui. Sinon, vous créez une situation où le ban fonctionne pour la moitié de l’Internet, ce qui n’est pas un succès enviable.
9) Fail2ban suffit‑il pour protéger SSH ?
C’est un réducteur de bruit utile et un limiteur de débit par bannissement. Mais les fondamentaux comptent encore davantage : authentification par clés, pas d’authentification par mot de passe si possible, MFA sur les bastions et exposition minimale au bord réseau.
10) Quel est le meilleur contrôle de sanity quand quelqu’un dit « Fail2ban ne marche pas » ?
Forcer un ban sur une IP de test, vérifier l’état du pare‑feu, puis vérifier le comportement des paquets. Cela isole l’application de la détection en quelques minutes.
Conclusion : prochaines étapes réalisables aujourd’hui
Si Fail2ban n’interdit rien sur Ubuntu 24.04, traitez‑le comme n’importe quel autre pipeline de production : entrée, traitement, sortie, application. Vérifiez chaque couche avec des preuves. Ne touchez pas aux réglages à l’aveugle.
Faites ces trois choses ensuite :
- Prouvez la visibilité des logs : confirmez que vos échecs existent là où le jail les lit (journal vs fichier), et exécutez
fail2ban-regexsur des données réelles. - Prouvez l’application : bannissez manuellement une IP de test et confirmez que des règles apparaissent dans le sous‑système de pare‑feu correct (nft vs iptables), puis validez le comportement avec des paquets.
- Rendez‑le répétable : ajoutez une petite étape de vérification post‑changement (ban, observer, unban) pour que les mises à jour n’isolent pas silencieusement vos défenses.
Fail2ban n’est pas magique. C’est une bonne nouvelle. Ça veut dire que vous pouvez le déboguer comme un adulte : avec un workflow, pas avec un vœu.