Remplacer fail2ban par l'agent Linux
Comment un hôte passe de fail2ban à l'agent sans interruption : vérifier d'abord à qui appartiennent déjà les objets du pare-feu, faire tourner les deux un moment, puis éteindre fail2ban pour de bon, et comment revenir en arrière en quelques secondes s'il le faut.
Remplacer fail2ban
L'agent ne se place pas à côté de fail2ban, il prend le relais. fail2ban reste disponible comme une source parmi d'autres, un hôte qui le fait encore tourner continue donc de signaler ses bannissements, et un hôte sans fail2ban ne perd rien : chaque type d'attaque qui arrivait par une jail a maintenant un détecteur qui lit le journal d'origine.
Mesuré sur onze jours sur un hôte de production : l'agent a trouvé 187 des 189 adresses que fail2ban
avait bannies sur la même machine, les deux manquantes étaient des adresses de test introduites à la
main, il a signalé 78 adresses de plus restées sous les seuils de fail2ban, et il a retrouvé les
bannissements FTP trois sur trois. L'escalade pour les récidivistes vient de l'historique de
bannissement propre à l'agent, et reportedip-agent test <file> prend la place
de fail2ban-regex.
Vérifier d'abord si quelque chose possède déjà ces noms
Cela a coûté un après-midi sur une flotte de production, c'est donc à lire avant tout le reste. Un
script de pare-feu écrit à la main, du genre que ce site documentait autrefois, peut employer
exactement les noms que l'agent emploie. Trouvés sur le terrain : les ensembles
rip-whitelist, rip-ssh, rip-mail, rip-web,
rip-ftp et rip-edge, plus une chaîne rip-blacklist accrochée
par -A INPUT -j rip-blacklist, reconstruite chaque heure par une tâche cron, et presque
caractère pour caractère la chaîne que l'agent construit lui-même.
Sur un tel hôte, l'ordre habituel est faux dans les deux sens. La première synchronisation de l'agent
reconstruit la chaîne et remplace les règles DROP existantes. Sur un hôte installé
avec --mode log, elle les remplace par des règles LOG, ce qui laisse l'hôte
sans protection jusqu'à la prochaine exécution de l'ancienne tâche cron, soit jusqu'à une heure plus
tard. Et quand cette tâche s'exécute, elle reconstruit la
chaîne à sa façon et retire au passage la règle rip-local de l'agent. Deux programmes,
une chaîne, et chacun défait le travail de l'autre toutes les heures.
Vérifiez donc avant la première synchronisation, et si les noms entrent en collision, n'installez pas
cet hôte avec --mode log. Installez l'agent, ce qui ne touche aucune règle, reprenez
l'ancienne liste blanche, désactivez l'ancienne tâche cron, et lancez seulement ensuite la première
synchronisation avec mode: drop, la valeur par défaut. Une phase d'observation avec
--mode log a sa place sur les hôtes où aucun nom n'entre en collision.
# 1. Does something already own these names?
ipset list -n | grep "^rip-"
iptables -S INPUT | grep rip-
iptables -S rip-blacklist 2>/dev/null | head
crontab -l | grep -iE "ipset|blacklist|reportedip"
ls -l /etc/cron.d/ /etc/cron.hourly/ 2>/dev/null
# 2. If yes, take the old whitelist over FIRST. The feed can be
# downloaded again; that list cannot.
ipset list rip-whitelist | sed -n "/^Members/,\$p" | tail -n +2 > /tmp/rip-wl
ipset list rip-whitelist-v6 | sed -n "/^Members/,\$p" | tail -n +2 >> /tmp/rip-wl
wc -l /tmp/rip-wl
while read -r a; do
[ -n "$a" ] && reportedip-agent whitelist add "$a" "imported from the old script"
done < /tmp/rip-wl
reportedip-agent whitelist list | wc -l
# 3. Disable the old job, then hand the chain over in one step.
crontab -l | grep -v blacklist | crontab - # or: rm /etc/cron.d/<job>
# Only if the agent was installed with --mode log:
sed -i "s/^mode: log/mode: drop/" /etc/reportedip-agent/config.yaml
reportedip-agent sync
reportedip-agent status
reportedip-agent whitelist list.
Faire tourner les deux un moment
Faire tourner les deux est sans danger et c'est la façon sensée de migrer. L'agent n'écrit jamais dans
/etc/fail2ban, et fail2ban ne sait rien des ensembles rip- : les deux
utilisent donc des chaînes séparées et des états séparés. Deux règles qui rejettent la même adresse
coûtent une comparaison de paquet.
La seule chose à éviter est de signaler le même événement deux fois. Si vous gardez l'action fail2ban qui envoie les bannissements par HTTP et que vous configurez fail2ban comme source de l'agent, chaque bannissement quitte l'hôte deux fois et est payé deux fois sur votre quota quotidien. Prenez l'agent ou l'action.
Installez avec REPORTEDIP_FAIL2BAN_SOURCE=0 quand vous remplacez
fail2ban. L'installateur détecte un fail2ban en marche et l'écrit comme source, ce qui est
juste pour un hôte qui le garde et faux pour une migration : une fois fail2ban parti, le journal
visé par cette source est parti aussi. La variable laisse la source de côté, et sans elle
l'installation affiche une ligne qui dit que la source est là et ce qu'il faut en faire après le
retrait. Sur un hôte déjà installé, retirez l'entrée fail2ban de sources
à la main, puis arrêtez et démarrez le service de surveillance.
# What did fail2ban ban, and what does the agent make of the
# same logs? Same file, same window, two verdicts.
fail2ban-client status sshd
reportedip-agent test /var/log/auth.log
# Per jail, then the agent over the file behind it
for j in $(fail2ban-client status | sed -n "s/.*Jail list:\t*//p" | tr -d " " | tr "," " "); do
echo "== $j"; fail2ban-client status "$j" | grep -E "Total banned|Currently banned"
done
reportedip-agent status | sed -n "/^sources:/,/^queue:/p"
Désactiver fail2ban définitivement
Faites-le une fois que vous avez comparé les deux pendant quelques jours et que la liste de sources de l'agent couvre chaque jail que vous aviez.
# 1. Stop it and keep it stopped.
systemctl stop fail2ban
systemctl disable fail2ban
# 2. Remove the fail2ban source from the agent config, then stop
# and start the daemon. A restart is not enough for a removed
# source: the daemon keeps tailing the old file.
$EDITOR /etc/reportedip-agent/config.yaml
systemctl stop reportedip-agent.service
systemctl start reportedip-agent.service
# 3. Check what fail2ban left in the kernel, in both address
# families. Stopping it does not always clean up: a jail that
# once used an iptables action leaves old-style f2b- chains behind.
nft list tables | grep f2b || echo "no f2b table"
iptables -S | grep "f2b-" || echo "no f2b chain (v4)"
ip6tables -S | grep "f2b-" || echo "no f2b chain (v6)"
ipset list -n | grep f2b || echo "no f2b set"
# 4. Remove the leftovers from the RUNNING ruleset. The jump rule
# carries -p and --dports, so it is deleted by its full text; a
# plain -D INPUT -j f2b-sshd does not match it, and the chain then
# refuses to go ("Device or resource busy"). Measured on a fleet:
# the v6 leftover was the one that stayed.
nft delete table inet f2b-table 2>/dev/null
for T in iptables ip6tables; do
$T -S INPUT | grep "f2b-" | sed "s/^-A INPUT //" | while read -r rule; do eval "$T -D INPUT $rule"; done
for c in $($T -S | awk "/^-N f2b-/{print \$2}"); do $T -F "$c" && $T -X "$c"; done
done
# 5. And from the SAVED one, or they come back at the next boot.
# Save without the rip- lines as well: the agent rebuilds its chain
# at every sync, and a saved rule that names a rip- set which does
# not exist yet at boot makes iptables-restore fail as a whole.
iptables-save | grep -v -e "f2b-" -e "rip-" > /etc/iptables/rules.v4
ip6tables-save | grep -v -e "f2b-" -e "rip-" > /etc/iptables/rules.v6
# 6. Confirm the agent is happy without it.
reportedip-agent status | grep -i fail2ban
reportedip-agent status; echo "exit $?"
f2b- seulement du jeu de règles en cours, netfilter-persistent les
restaure à chaque démarrage depuis /etc/iptables/rules.v4 et depuis
/etc/iptables/rules.v6. Elles reviennent vides, donc elles ne rejettent rien et
paraissent inoffensives, et dans un an elles seront encore là à embrouiller la personne suivante
qui lira le jeu de règles. Examinez les deux fichiers : sur un hôte, les restes n'étaient que
dans le fichier v6, et qui ne cherche que dans rules.v4 passe à côté. D'abord
nettoyer le jeu de règles en cours, puis l'enregistrer, et vérifier après un redémarrage.
Un retour arrière est une commande et prend quelques secondes, car l'agent n'a jamais touché à
/etc/fail2ban : systemctl enable --now fail2ban ramène chaque jail et sa
propre table, et l'agent n'en est pas affecté. Mesuré sur un hôte en production, les onze jails étaient
revenues en huit secondes.
Dernière mise à jour: · Maintenu par l’équipe ReportedIP