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,32 @@
|
||||
[Unit]
|
||||
Description=Fail2banActionBanisher - émetteur : relais vers le master (master_client, SYNC_BAN)
|
||||
After=network.target mosquitto.service
|
||||
Requires=mosquitto.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=__EMITTER_USER__
|
||||
Group=__EMITTER_GROUP__
|
||||
WorkingDirectory=__EMITTER_DIR__
|
||||
EnvironmentFile=__ENV_FILE__
|
||||
Environment=DJANGO_SETTINGS_MODULE=config.settings.production
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
ExecStart=__EMITTER_DIR__/.venv/bin/python manage.py master_client
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Pas de NoNewPrivileges=true ici, contrairement aux autres services de
|
||||
# l'émetteur : ce process a structurellement besoin d'escalader via sudo
|
||||
# (execute_sync_ban -> `sudo fail2ban-client set master-sync banip <ip>`,
|
||||
# cf. master_client.py). NoNewPrivileges bloque tout mécanisme de gain de
|
||||
# privilège au niveau execve, y compris le setuid de sudo lui-même — sudo
|
||||
# échoue alors avec "the 'no new privileges' flag is set", quels que soient
|
||||
# les droits sudoers. Repéré seulement en conditions réelles (le premier
|
||||
# vrai SYNC_BAN reçu d'un autre noeud) : les tests précédents mockaient
|
||||
# subprocess.run, donc n'exerçaient jamais cette interaction avec systemd.
|
||||
ProtectSystem=strict
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=__EMITTER_DIR__
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Fail2banActionBanisher - émetteur : ingestion master (master_listen, tous les noeuds)
|
||||
After=network.target mosquitto.service
|
||||
Requires=mosquitto.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=__EMITTER_USER__
|
||||
Group=__EMITTER_GROUP__
|
||||
WorkingDirectory=__EMITTER_DIR__
|
||||
EnvironmentFile=__ENV_FILE__
|
||||
Environment=DJANGO_SETTINGS_MODULE=config.settings.production
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
ExecStart=__EMITTER_DIR__/.venv/bin/python manage.py master_listen
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=__EMITTER_DIR__
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Fail2banActionBanisher - émetteur : ingestion MQTT (mqtt_listen)
|
||||
After=network.target mosquitto.service
|
||||
Requires=mosquitto.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=__EMITTER_USER__
|
||||
Group=__EMITTER_GROUP__
|
||||
WorkingDirectory=__EMITTER_DIR__
|
||||
EnvironmentFile=__ENV_FILE__
|
||||
Environment=DJANGO_SETTINGS_MODULE=config.settings.production
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
ExecStart=__EMITTER_DIR__/.venv/bin/python manage.py mqtt_listen
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=__EMITTER_DIR__
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,62 @@
|
||||
[Unit]
|
||||
Description=Fail2banActionBanisher - émetteur Django (ASGI/Daphne)
|
||||
After=network.target redis-server.service
|
||||
Requires=redis-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=__EMITTER_USER__
|
||||
Group=__EMITTER_GROUP__
|
||||
WorkingDirectory=__EMITTER_DIR__
|
||||
EnvironmentFile=__ENV_FILE__
|
||||
Environment=DJANGO_SETTINGS_MODULE=config.settings.production
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
# Loopback uniquement par défaut : éditer le bind ici pour un accès distant
|
||||
# (ex. IP du VPN de confiance), pas d'exposition publique directe prévue.
|
||||
ExecStart=__EMITTER_DIR__/.venv/bin/daphne -b 127.0.0.1 -p 8050 config.asgi:application
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Pas de NoNewPrivileges=true ici (retiré 2026-07-18) : depuis l'endpoint
|
||||
# /api/join/ (banevents/views.py::join_node, auto-inscription des noeuds
|
||||
# par jeton), ce process a structurellement besoin d'escalader via sudo
|
||||
# (sudo scripts/sign-node-csr.sh ...). Même piège déjà rencontré sur
|
||||
# fail2ban-emitter-master-client.service : NoNewPrivileges bloque tout
|
||||
# mécanisme de gain de privilège au niveau execve, y compris le setuid de
|
||||
# sudo lui-même — sudo échoue alors avec "the 'no new privileges' flag is
|
||||
# set", quels que soient les droits sudoers. Repéré en conditions réelles
|
||||
# (premier vrai test de /api/join/), pas en lecture de code.
|
||||
ProtectSystem=strict
|
||||
PrivateTmp=true
|
||||
# /etc/mosquitto/master-ca et master-acl.conf : sign-node-csr.sh (appelé
|
||||
# via sudo par /api/join/) écrit un fichier .srl à côté de ca.crt
|
||||
# (-CAcreateserial d'openssl) ET ajoute l'entitlement ACL du nouveau
|
||||
# noeud — sudo ne crée pas de nouveau mount namespace, le sudo'd child
|
||||
# hérite du même ProtectSystem=strict que ce process, donc ces deux
|
||||
# chemins doivent être listés ici aussi, pas seulement __EMITTER_DIR__.
|
||||
# Repéré en conditions réelles (premier vrai test de /api/join/, échec
|
||||
# silencieux : openssl/l'ajout ACL échouaient sans qu'aucun message ne
|
||||
# remonte jusqu'au subprocess.run() de la vue Django).
|
||||
#
|
||||
# Préfixe "-" obligatoire sur les deux chemins mosquitto : CE service
|
||||
# tourne sur TOUS les noeuds (unité générique), pas seulement le master —
|
||||
# /etc/mosquitto/master-ca et master-acl.conf n'existent QUE sur le
|
||||
# master (déployés par install-master). ReadWritePaths= exige que le
|
||||
# chemin existe déjà au moment de construire le mount namespace ; sans
|
||||
# "-", le service refuse de démarrer PARTOUT ailleurs que sur le master
|
||||
# ("Failed to set up mount namespacing: ... No such file or directory",
|
||||
# status 226/NAMESPACE) — cassé en conditions réelles sur un vrai noeud
|
||||
# (linuxtarn-vps1) le jour même du déploiement. "-" en tête dit à systemd
|
||||
# d'ignorer silencieusement l'entrée si le chemin est absent.
|
||||
# /var/spool/exim4 et /var/log/exim4 : django-sendmail-backend invoque
|
||||
# /usr/sbin/sendmail directement (voir config/settings/base.py) pour
|
||||
# l'email d'inscription à la communauté (banevents/views.py::
|
||||
# community_landing, mail_admins) — même piège que ci-dessus, repéré en
|
||||
# conditions réelles : "Cannot open main log file ... Permission denied"
|
||||
# + "Failed to create spool file ... Read-only file system". Préfixe "-"
|
||||
# : un noeud sans exim4 installé ne doit pas empêcher ce service de
|
||||
# démarrer.
|
||||
ReadWritePaths=__EMITTER_DIR__ -/etc/mosquitto/master-ca -/etc/mosquitto/master-acl.conf -/var/spool/exim4 -/var/log/exim4
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Fail2banActionBanisher - émetteur : worker Celery (géolocalisation)
|
||||
After=network.target redis-server.service
|
||||
Requires=redis-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=__EMITTER_USER__
|
||||
Group=__EMITTER_GROUP__
|
||||
WorkingDirectory=__EMITTER_DIR__
|
||||
EnvironmentFile=__ENV_FILE__
|
||||
Environment=DJANGO_SETTINGS_MODULE=config.settings.production
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
ExecStart=__EMITTER_DIR__/.venv/bin/celery -A config worker -l info
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=__EMITTER_DIR__
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,18 @@
|
||||
# Log dédié aux verrouillages django-axes (emitter/logs/admin-auth.log,
|
||||
# cf. LOGGING dans config/settings/base.py et
|
||||
# generic/fail2ban/jail.d/emitter-admin-auth.conf) — aucun logrotate.d
|
||||
# système ne le couvre (chemin custom sous le home du user de déploiement,
|
||||
# pas /var/log). copytruncate, pas le rename+recreate par défaut : le
|
||||
# logging.FileHandler de Python garde son descripteur de fichier ouvert
|
||||
# tant que le process (Daphne) tourne, il ne le rouvrirait jamais tout
|
||||
# seul après un rename — copytruncate tronque le fichier EN PLACE (même
|
||||
# inode), pas besoin de redémarrer le service pour rotation.
|
||||
__EMITTER_DIR__/logs/admin-auth.log {
|
||||
weekly
|
||||
rotate 6
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
copytruncate
|
||||
}
|
||||
Reference in New Issue
Block a user