2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00
2026-07-20 11:05:07 +02:00

Fail2banActionBanishment

Système distribué de bannissement d'hôtes malveillants basé sur fail2ban et iptables, avec propagation des événements par MQTT.

Chaque noeud détecte et bannit localement (fail2ban + iptables), publie l'événement sur un broker Mosquitto local, puis relaie l'information vers un broker master privé. Le master centralise la décision (corrélation multi-noeuds, récidive globale, réputation partagée) et republie les actions à exécuter vers l'ensemble des noeuds abonnés.

Machine cible : VPS Debian 13.

Documentation complète (installation, déploiement en production détaillé, auto-inscription des noeuds, référence des topics MQTT et des commandes) : make docs-serve puis http://127.0.0.1:8001/, ou make docs pour générer le site statique dans site/. Voir aussi README-EN.md pour la version anglaise.

Architecture (résumé)

[noeud] fail2ban/iptables → mosquitto local (1883) → mosquitto master (8883, TLS)
                                                              │
                                                    décision / corrélation
                                                              │
[noeud] ◄──────────────── action MQTT (BAN, SYNC_BAN, UNBAN, ...) ◄──────────

Cas d'usage

Le modèle master/noeuds ne suppose aucun lien d'appartenance entre les serveurs protégés — seulement qu'ils partagent une même autorité de décision. Ça rend l'architecture pertinente au-delà d'un opérateur unique sur ses propres VPS :

  • Un ensemble de sites (plusieurs VPS d'un même opérateur, chacun hébergeant un ou plusieurs services) : une IP qui attaque un site est bannie partout via SYNC_BAN, sans surveillance manuelle site par site.
  • Une communauté (plusieurs administrateurs indépendants, chacun responsable de son propre serveur, qui acceptent de mutualiser leurs détections) : chaque membre garde son propre noeud et son propre fail2ban local — seule la propagation des bans est partagée via le master commun. Aucun accès aux serveurs des autres membres n'est requis ni accordé.
  • Une société de services informatiques qui gère les sites de plusieurs clients : un master centralisé donne une vue agrégée (compteurs jail/pays, historique par noeud, alias par client) sans mélanger les données de client à client — chaque noeud ne voit que ses propres événements, le master voit tout.

Dans les trois cas, un nouveau serveur rejoint l'ensemble sans jamais donner accès SSH aux autres : une auto-inscription par jeton à usage unique suffit (make join-token / make join, détaillé plus bas).

Contenu du dépôt

  • generic/fail2ban/ — jails, filtres et action MQTT (f2b-mqtt-action-banisher)
  • generic/firewall/ — script iptables (firewall-launcher.sh), règles par service
  • generic/mosquitto/ — broker MQTT local (127.0.0.1:1883, sans persistance) et broker master (mosquitto-master.conf, port 8883, mTLS)
  • generic/emitter/ — gabarits des services systemd (web/ASGI, ingestion MQTT, worker Celery, relais master)
  • generic/supervisor/ — gabarits .example.conf (alternative optionnelle à systemd, make install-supervisor)
  • generic/nginx/ — gabarit .example.conf de reverse proxy TLS devant le tableau de bord (non déployé automatiquement)
  • emitter/ — émetteur Django (app banevents) : ingestion MQTT (manage.py mqtt_listen), relais vers le master (manage.py master_client), modèle BanEvent, tableau de bord + carte + historique, géolocalisation (Celery)
  • .env.example — modèle de configuration (copié vers .env par install.sh, jamais committé)
  • install.sh — déploiement idempotent (paquets, fichiers de conf, services systemd, y compris l'émetteur) ; wrappé par les cibles make ci-dessous
  • scripts/test-fail2ban-filters.sh — vérification des filtres custom via fail2ban-regex
  • scripts/master-ca-init.sh, scripts/generate-node-cert.sh — CA privée et certificats clients mTLS pour le broker master (flux manuel, voir auto-inscription plus bas pour le flux recommandé)
  • Makefile — tous les points d'entrée (make help pour la liste complète)
  • docs/ — documentation mkdocs (installation, déploiement en production, référence)

Installation (VPS Debian 13)

Modèle de déploiement : pas de copie vers /opt. Le dépôt cloné dans le $HOME d'un utilisateur dédié (ex. banisher) est le déploiement — venv, base SQLite, staticfiles/ et .env vivent tous dans ce checkout, possédés par cet utilisateur. install.sh détecte cet utilisateur à partir du propriétaire du dépôt (pas de nom codé en dur) :

useradd -m -s /bin/bash banisher   # une seule fois, si le compte n'existe pas
su - banisher -c 'git clone <url-du-dépôt> ~/Fail2banMqttActionBanisher'
cd ~banisher/Fail2banMqttActionBanisher
sudo make install
sudo make status

make install (= sudo ./install.sh install) :

  • installe/vérifie un sudoers NOPASSWD:ALL pour cet utilisateur (/etc/sudoers.d/<user>-full-access, créé une seule fois s'il est absent) — ce compte doit donc être dédié à ce projet, pas un compte partagé avec d'autres usages ;
  • copie .env.example vers .env s'il est absent (jamais régénéré ensuite, DJANGO_SECRET_KEY généré aléatoirement) — éditer .env pour les vrais identifiants (mot de passe MQTT du compte emitter, domaine du master, ...) ;
  • crée le venv Python de l'émetteur (emitter/.venv), applique les migrations et collectstatic, tous exécutés en tant que l'utilisateur de déploiement (jamais root) ;
  • active quatre services systemd : fail2ban-emitter-web (tableau de bord ASGI/Daphne, 127.0.0.1:8050), fail2ban-emitter-mqtt (manage.py mqtt_listen), fail2ban-emitter-worker (worker Celery, géolocalisation) et fail2ban-emitter-master-client (manage.py master_client, relais/exécution des commandes du master — ne se connectera réellement qu'une fois un certificat de noeud obtenu, voir plus bas).

Éditer aussi /etc/fail2ban/mqtt.conf (identifiants MQTT réels, copié depuis generic/fail2ban/mqtt.conf.example s'il n'existe pas encore).

Pour mettre à jour l'émetteur après un git pull, relancer simplement sudo make install : les dépendances/migrations sont réappliquées et les quatre services redémarrés.

Options de déploiement supplémentaires (détaillées dans la documentation de déploiement, make docs-serve pour la version navigable) :

  • master (sudo make install-master) — broker MQTT public en mTLS, CA privée, ingestion multi-noeuds ;
  • auto-inscription d'un noeud (make join-token côté master, puis sudo make join côté nouveau noeud) — recommandé pour rattacher un noeud à un master, sans jamais copier de certificat à la main ;
  • nginx (sudo make install-nginx) — reverse proxy TLS (Let's Encrypt) devant le tableau de bord, pour un accès public ;
  • supervisor (sudo make install-supervisor / sudo make uninstall-supervisor) — alternative optionnelle à systemd ;
  • MariaDB (sudo make install-mariadb) — bascule la base de données de SQLite (défaut) vers un serveur MariaDB local dédié.

Émetteur Django (développement)

Nécessite un Redis accessible (channel layer Django Channels, ex. docker run -p 6379:6379 redis).

make run       # tableau de bord + carte sur http://127.0.0.1:8000/ (WebSocket temps réel inclus)
make mqtt      # dans un second terminal : ingestion MQTT
make worker    # dans un troisième terminal : géolocalisation asynchrone

Variables d'environnement (MQTT_BROKER_HOST, MQTT_BROKER_USERNAME, MQTT_BROKER_PASSWORD, REDIS_HOST, REDIS_PORT, ...) : copier .env.example vers .env à la racine du dépôt et l'éditer — chargé automatiquement par Django (python-dotenv) sans rien à exporter à la main. La géolocalisation utilise l'API externe gratuite ip-api.com en attendant une base GeoLite2 (MaxMind) locale.

Traductions (fr/en)

Le français est la langue source du code des templates ; l'anglais est une traduction maintenue dans emitter/locale/en/LC_MESSAGES/django.po. Un sélecteur dans la sidebar du tableau de bord bascule la langue active (cookie django_language).

Après avoir ajouté/modifié un {% trans %}/{% blocktrans %} dans un template :

cd emitter
.venv/bin/python manage.py makemessages -l en --no-location --ignore ".venv"
# éditer locale/en/LC_MESSAGES/django.po (remplir les msgstr manquants)
.venv/bin/python manage.py compilemessages -l en --ignore ".venv"

--ignore ".venv" : sans ça, compilemessages recompile aussi (lentement, sans effet utile) toutes les traductions internes de Django trouvées dans le venv, puisque celui-ci vit sous emitter/ — inoffensif mais inutile.

Broker master et auto-inscription des noeuds

Voir la documentation de déploiement pour le détail complet : provisionnement du master, modèle de sécurité de l'auto-inscription (jeton à usage unique, clé privée qui ne quitte jamais le noeud, jeton rendu automatiquement en cas d'échec transitoire), dépannage. En résumé :

# sur le master
make join-token NODE=mon-noeud

# sur le nouveau noeud
sudo make join MASTER=https://dashboard-du-master NODE=mon-noeud TOKEN=<jeton>
sudo make install

L'ingestion côté master (manage.py master_listen) republie systématiquement un SYNC_BAN pour chaque ban ingéré, et corrèle les bans indépendants sur plusieurs noeuds pour déclencher une escalade automatique — voir la référence pour la liste complète des commandes du master et des topics MQTT.

Contraintes de développement

  • Code source en anglais, commentaires en français
  • Indentation : 4 espaces, jamais de tabulation, voir .editorconfig (exception : les recettes du Makefile, qui doivent être indentées par une tabulation — contrainte de l'outil Make lui-même)
  • Python vérifié avec pyright (pyrightconfig.json), scripts shell avec shellcheckmake lint, aussi exécuté en CI
  • JavaScript : classes ES6

Licence

AGPL-3.0 — voir LICENSE.

S
Description
Système distribué de bannissement d'hôtes malveillants basé sur fail2ban et iptables, avec propagation des événements par MQTT.
Readme AGPL-3.0 333 KiB
Languages
Python 43.6%
Shell 23.6%
CSS 11.2%
INI 9.2%
HTML 7.4%
Other 5%