
Exposez un port SSH sur Internet et regardez les journaux : les tentatives arrivent en continu, par milliers, depuis des botnets qui essaient des couples utilisateur/mot de passe en boucle. Fail2ban est la réponse classique : lire les journaux, repérer les échecs répétés, bannir l'adresse source. Cinq minutes à installer, et c'est bien le problème : la plupart des installations en restent au tutoriel, avec une jail SSH par défaut qui rassure plus qu'elle ne protège. Voici ce que change une configuration de production, pièges vécus compris.
Remettre fail2ban à sa place
Disons-le d'abord clairement : fail2ban est un réducteur de bruit, pas une défense principale. Si votre SSH accepte les mots de passe, fail2ban ralentit les attaquants ; si votre SSH n'accepte que les clés (PasswordAuthentication no), le brute force est déjà mort : fail2ban ne fait plus qu'assainir les journaux et économiser des ressources. L'ordre des priorités est donc : authentification par clé uniquement, exposition minimale (un pare-feu qui n'ouvre que le nécessaire, des allowlists d'IP pour l'administration), et ensuite fail2ban pour le bruit résiduel. C'est l'architecture de nos serveurs frontaux : le pare-feu de l'hyperviseur ne laisse passer que HTTP/HTTPS du public, SSH est sur clé, et fail2ban nettoie ce qui reste.
La base, version 2026 : journald, pas auth.log
Premier piège des tutoriels anciens : ils pointent fail2ban vers /var/log/auth.log… qui n'existe plus sur les systèmes modernes sans rsyslog, où tout vit dans le journal systemd. Une jail qui lit un fichier absent ou gelé ne banni personne, en silence. La parade : backend = systemd. Voici notre socle jail.local, avec le second réglage qui change tout, le bannissement progressif :
# /etc/fail2ban/jail.local
[DEFAULT]
backend = systemd
banaction = nftables-multiport
# Bannissement progressif : chaque récidive multiplie la peine.
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
findtime = 10m
maxretry = 5
# IP à ne JAMAIS bannir : supervision, admin. Liste courte et justifiée.
ignoreip = 127.0.0.1/8 ::1 <ip-supervision>
[sshd]
enabled = true
mode = aggressiveLe progressif est ce qui fait la différence sur la durée : un scanner occasionnel prend une heure, un récidiviste finit banni une semaine. Et vérifiez toujours qu'une jail travaille réellement : fail2ban-client status sshd doit montrer des correspondances qui augmentent : une jail à zéro depuis des semaines sur un serveur exposé est une jail cassée, pas un serveur épargné.
L'étage au-dessus : les jails HTTP derrière un reverse proxy
Le brute force ne vise pas que SSH : les pages de connexion des applications web, les endpoints d'API et les chemins d'administration prennent le même trafic. Fail2ban sait les protéger, à condition de lire les journaux du reverse proxy (Traefik, nginx…) et d'y matcher les rafales de 401/403. Deux conditions non négociables, toutes deux apprises à nos dépens :
- Bannir la vraie IP client, jamais celle du proxy. Si votre application est derrière un reverse proxy (ou pire, si Docker fait du NAT devant), les journaux peuvent n'afficher que l'IP interne du proxy. Bannissez-la et vous coupez tout le trafic. Il faut que la chaîne préserve l'adresse source de bout en bout ; sur l'un de nos serveurs, cela a imposé de passer le proxy en réseau hôte, faute de quoi les visiteurs IPv6 apparaissaient tous avec la même IP interne de passerelle Docker.
- Journaux structurés. Un access log JSON se parse sans regex fragile : le filtre fail2ban devient une ligne fiable au lieu d'une expression qui casse à la première mise à jour du format.
Les deux pièges qui coûtent cher
Le proxy d'entreprise : une IP = des dizaines d'humains
Vécu en production : des rafales de requêtes suspectes depuis une IP unique, le réflexe de bannir… et c'était un proxy d'entreprise (type Zscaler) : derrière cette adresse, des dizaines de salariés légitimes, dont peut-être votre client. Même chose pour les sondes de supervision externes, dont le comportement (requêtes régulières, ports variés) ressemble à s'y méprendre à un scan. Avant de bannir une IP « bizarre », un whois prend dix secondes ; les proxys d'entreprise et vos sondes vont dans ignoreip, documentés, avec la raison en commentaire.
nftables : le restart qui purge tout
Fail2ban écrit ses bannissements dans le pare-feu (nftables aujourd'hui). Or systemctl restart nftables purge l'intégralité du ruleset avant de recharger le fichier, emportant les tables dynamiques de fail2ban et, si Docker tourne, ses règles NAT : nous avons vu un restart anodin couper le DNS d'un conteneur en production. Pour recharger une configuration nftables, utilisez nft -f (atomique, additif), jamais un restart du service sur une machine qui porte fail2ban ou Docker.
Fail2ban illustre bien notre conviction : la sécurité n'est pas un produit qu'on installe, c'est une série de détails qu'on vérifie. C'est ce que couvre notre infogérance : durcissement, supervision des jails, et sauvegardes immuables pour le jour où tout le reste a échoué. Un doute sur l'exposition réelle de vos serveurs ? Parlons-en.


