mirror of
https://github.com/deunix-educ/Fail2banMqttActionBanishment.git
synced 2026-08-24 03:11:58 +02:00
First commit
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
# 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](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) :
|
||||
|
||||
```sh
|
||||
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](docs/deployment.md), `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`).
|
||||
|
||||
```sh
|
||||
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 :
|
||||
|
||||
```sh
|
||||
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](docs/deployment.md) 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é :
|
||||
|
||||
```sh
|
||||
# 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](docs/reference.md) 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
|
||||
`shellcheck` — `make lint`, aussi exécuté en CI
|
||||
- JavaScript : classes ES6
|
||||
|
||||
## Licence
|
||||
|
||||
AGPL-3.0 — voir [LICENSE](LICENSE).
|
||||
Reference in New Issue
Block a user