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:
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# certbot-deploy-mosquitto.sh — copie le certificat Let's Encrypt vers un
|
||||
# emplacement lisible par l'utilisateur système 'mosquitto' (non-root), et
|
||||
# redémarre mosquitto pour qu'il recharge le nouveau certificat.
|
||||
#
|
||||
# /etc/letsencrypt est verrouillé root-only par certbot (le dossier lui-même,
|
||||
# pas seulement privkey.pem) : mosquitto ne peut donc jamais lire les
|
||||
# fichiers directement à leur emplacement d'origine, quels que soient leurs
|
||||
# propres droits. D'où cette copie découplée, dans un répertoire que install.sh
|
||||
# rend group-lisible pour 'mosquitto'.
|
||||
#
|
||||
# Installé par install.sh (install-master) comme deploy-hook certbot :
|
||||
# /etc/letsencrypt/renewal-hooks/deploy/ — s'exécute automatiquement à
|
||||
# chaque renouvellement. Peut aussi être lancé à la main.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DOMAIN="__MQTT_MASTER_DOMAIN__"
|
||||
SRC="/etc/letsencrypt/live/$DOMAIN"
|
||||
DEST="/etc/mosquitto/master-tls"
|
||||
|
||||
install -d -o root -g mosquitto -m 750 "$DEST"
|
||||
cp "$SRC/fullchain.pem" "$DEST/fullchain.pem"
|
||||
cp "$SRC/privkey.pem" "$DEST/privkey.pem"
|
||||
chown root:mosquitto "$DEST/fullchain.pem" "$DEST/privkey.pem"
|
||||
chmod 640 "$DEST/fullchain.pem" "$DEST/privkey.pem"
|
||||
|
||||
systemctl restart mosquitto.service
|
||||
@@ -0,0 +1,38 @@
|
||||
# ACL du broker master — %u est le CN du certificat client (cf.
|
||||
# use_identity_as_username dans mosquitto-master.conf). Chaque noeud ne peut
|
||||
# publier que sous son propre topic de ban, et ne lire que ses propres
|
||||
# commandes plus le canal de diffusion générale.
|
||||
#
|
||||
# Déployé par install.sh (install-master) vers /etc/mosquitto/master-acl.conf
|
||||
|
||||
pattern write fail2ban/%u/ban
|
||||
# heartbeat (Phase 3, supervision) : chaque noeud publie périodiquement
|
||||
# pour prouver qu'il est vivant, indépendamment de toute activité de ban.
|
||||
# ack (Phase 2.b) : accusé de réception publié après exécution réelle d'une
|
||||
# commande reçue du master (ex. SYNC_BAN), succès ou échec.
|
||||
pattern write fail2ban/%u/heartbeat
|
||||
pattern write fail2ban/%u/ack
|
||||
pattern read fail2ban/%u/action
|
||||
|
||||
# Topic fixe (identique pour tous les noeuds) : "topic", pas "pattern" —
|
||||
# "pattern" est réservé aux entrées substituées par client (%u/%c) et
|
||||
# mosquitto avertit (pattern ignoré) si on l'utilise sans placeholder.
|
||||
topic read fail2ban/broadcast/action
|
||||
|
||||
# Identité dédiée à l'ingestion/décision côté master
|
||||
# (banevents.master_listen) : lecture de fail2ban/+/ban (TOUS les noeuds),
|
||||
# et écriture sur le canal de diffusion (pour publier un SYNC_BAN) — deux
|
||||
# droits plus larges que ceux d'un noeud pris individuellement (pattern
|
||||
# ci-dessus, limité à fail2ban/%u/ban). "user <nom>" scope les règles
|
||||
# suivantes à cette seule identité de certificat — généré via
|
||||
# scripts/generate-node-cert.sh master-internal.
|
||||
user master-internal
|
||||
topic read fail2ban/+/ban
|
||||
topic read fail2ban/+/heartbeat
|
||||
topic read fail2ban/+/ack
|
||||
topic write fail2ban/broadcast/action
|
||||
# Roster périodique (Phase 3) : liste des noeuds connus + compteurs
|
||||
# jail/pays globaux, republié localement par chaque noeud (NodeRegistry +
|
||||
# cache Redis, voir banevents/stats.py) — sans ça la sidebar d'un noeud
|
||||
# client n'aurait jamais que ses propres données.
|
||||
topic write fail2ban/broadcast/roster
|
||||
@@ -0,0 +1,41 @@
|
||||
# Broker Mosquitto local — consommé par f2b-mqtt-action-banisher et par
|
||||
# l'emetteur Django (Phase 2). Jamais exposé sur Internet : écoute en
|
||||
# loopback, plus (optionnellement, cf. MQTT_VPN_LISTENER_IP dans .env) un
|
||||
# listener additionnel sur le réseau VPN de confiance de CE noeud, pour
|
||||
# permettre le développement/test de l'émetteur depuis un poste distant sur
|
||||
# ce VPN. Cette IP est propre à chaque VPS (jamais une valeur partagée
|
||||
# entre noeuds) — install.sh (deploy_mosquitto) remplace le marqueur
|
||||
# ci-dessous à partir de .env, ou le retire entièrement si
|
||||
# MQTT_VPN_LISTENER_IP est vide. NE PAS répéter ce marqueur ailleurs dans ce
|
||||
# fichier, y compris en commentaire : la substitution est un remplacement
|
||||
# global (gsub), toute autre occurrence littérale serait aussi affectée.
|
||||
#
|
||||
# Déployé par install.sh vers /etc/mosquitto/conf.d/mosquitto-local.conf
|
||||
|
||||
per_listener_settings true
|
||||
|
||||
# Avec per_listener_settings, allow_anonymous/password_file doivent être
|
||||
# répétés sous chaque listener : ils ne s'appliquent qu'au listener sous
|
||||
# lequel ils apparaissent, jamais rétroactivement aux précédents.
|
||||
listener 1883 127.0.0.1
|
||||
protocol mqtt
|
||||
allow_anonymous false
|
||||
password_file /etc/mosquitto/passwd_local
|
||||
|
||||
__VPN_LISTENER_BLOCK__
|
||||
|
||||
# Pas de persistance : les événements sont consommés en temps réel,
|
||||
# aucun besoin de rejouer l'historique après un redémarrage du broker.
|
||||
persistence false
|
||||
|
||||
# Pas de log_dest ici : /etc/mosquitto/mosquitto.conf (paquet Debian) en
|
||||
# déclare déjà un ("log_dest file /var/log/mosquitto/mosquitto.log"),
|
||||
# lu avant ce conf.d — en rajouter un second (même en syslog) fait
|
||||
# planter mosquitto au chargement ("Duplicate 'log_dest file' value").
|
||||
# C'est précisément ce fichier que surveille la jail fail2ban "mosquitto"
|
||||
# (jail.d/mosquitto.conf) : si jamais un jour ce défaut du paquet
|
||||
# disparaît/change, il faudra le redéclarer ici explicitement plutôt que
|
||||
# supposer qu'il existe toujours.
|
||||
log_type error
|
||||
log_type warning
|
||||
log_type notice
|
||||
@@ -0,0 +1,33 @@
|
||||
# Broker Mosquitto master (Phase 3) — écoute 8883, TLS obligatoire.
|
||||
# Cohabite avec le listener local (mosquitto-local.conf) dans le même
|
||||
# processus mosquitto : per_listener_settings s'applique par listener, pas
|
||||
# de conflit entre les deux fichiers de conf.d.
|
||||
#
|
||||
# Deux chaînes de confiance distinctes :
|
||||
# - certfile/keyfile : certificat Let's Encrypt du domaine __MQTT_MASTER_DOMAIN__
|
||||
# (identité TLS présentée par le serveur) — copié par
|
||||
# certbot-deploy-mosquitto.sh vers /etc/mosquitto/master-tls/, jamais lu
|
||||
# directement dans /etc/letsencrypt/ (verrouillé root-only par certbot,
|
||||
# illisible pour l'utilisateur système 'mosquitto')
|
||||
# - cafile : CA privée dédiée (scripts/master-ca-init.sh), qui NE SERT QU'À
|
||||
# vérifier les certificats clients des noeuds (mTLS) — Let's Encrypt ne
|
||||
# signe pas de certificats clients.
|
||||
#
|
||||
# Déployé par install.sh (install-master) vers /etc/mosquitto/conf.d/mosquitto-master.conf
|
||||
|
||||
listener 8883
|
||||
protocol mqtt
|
||||
|
||||
cafile /etc/mosquitto/master-ca/ca.crt
|
||||
certfile /etc/mosquitto/master-tls/fullchain.pem
|
||||
keyfile /etc/mosquitto/master-tls/privkey.pem
|
||||
tls_version tlsv1.2
|
||||
|
||||
# mTLS : le certificat client est obligatoire, et son CN devient l'identité
|
||||
# MQTT du noeud (exploité par master-acl.conf pour restreindre chaque noeud
|
||||
# à ses propres topics).
|
||||
require_certificate true
|
||||
use_identity_as_username true
|
||||
allow_anonymous false
|
||||
|
||||
acl_file /etc/mosquitto/master-acl.conf
|
||||
@@ -0,0 +1,40 @@
|
||||
# Renforcement du service mosquitto par défaut du paquet Debian.
|
||||
# L'utilisateur dédié "mosquitto" est déjà créé par le paquet ; ce drop-in
|
||||
# ne fait que restreindre ses droits système.
|
||||
#
|
||||
# Déployé par install.sh vers /etc/systemd/system/mosquitto.service.d/override.conf
|
||||
|
||||
[Service]
|
||||
# User=/Group= explicites : sans ça, RuntimeDirectory= (ci-dessous) crée
|
||||
# /run/mosquitto appartenant à root (propriétaire par défaut quand User=
|
||||
# est vide), car ce chemin est bind-monté dans le namespace propre à
|
||||
# ExecStart avec cette ownership-là — le `chown mosquitto:mosquitto
|
||||
# /run/mosquitto` du ExecStartPre du paquet Debian n'a aucun effet
|
||||
# persistant sur cette vue. Résultat observé : mosquitto démarre root,
|
||||
# abandonne ses privilèges en interne vers l'utilisateur "mosquitto"
|
||||
# (aucune directive "user" dans mosquitto.conf nécessaire, comportement
|
||||
# par défaut du binaire), puis échoue avec "Unable to write pid file"
|
||||
# (EACCES sur /run/mosquitto/mosquitto.pid, confirmé via strace). Fixer
|
||||
# User=/Group= ici fait créer /run/mosquitto directement avec le bon
|
||||
# propriétaire, sans dépendre du chown du ExecStartPre.
|
||||
User=mosquitto
|
||||
Group=mosquitto
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=/var/lib/mosquitto /var/log/mosquitto
|
||||
# /run/mosquitto est du tmpfs, recréé à chaque démarrage : lister ce chemin
|
||||
# dans ReadWritePaths= exige qu'il existe déjà AVANT que systemd ne monte le
|
||||
# namespace de l'unité (donc avant même le premier ExecStartPre), ce que
|
||||
# rien ne garantit après un redémarrage du VPS ("Failed to set up mount
|
||||
# namespacing: /run/mosquitto: No such file or directory", 226/NAMESPACE).
|
||||
# RuntimeDirectory= est le mécanisme systemd natif pour ce cas précis : il
|
||||
# crée /run/mosquitto (proprio mosquitto, cf. User=/Group= ci-dessus) lui-
|
||||
# même, avant tout Exec*, et le recrée à chaque démarrage — pas de
|
||||
# dépendance sur un état laissé par un run précédent.
|
||||
RuntimeDirectory=mosquitto
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
Reference in New Issue
Block a user