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

71 lines
3.0 KiB
Bash
Executable File

#!/bin/bash
# sign-node-csr.sh — signe une CSR de noeud avec la CA privée du master,
# ajoute l'entitlement ACL nécessaire, redémarre mosquitto. Coeur commun à
# generate-node-cert.sh (flux manuel) et à l'endpoint /api/join/ (flux par
# jeton, banevents/views.py::join_node) — un seul chemin de code qui
# touche ca.key, pas deux implémentations à maintenir en parallèle.
#
# Usage : sudo ./sign-node-csr.sh <nom_du_noeud> <fichier_csr>
# Écrit le certificat signé (PEM) sur STDOUT — tous les messages
# informatifs/d'erreur vont sur STDERR, pour que stdout reste exploitable
# programmatiquement (ex. capturé tel quel par un appelant Python).
set -euo pipefail
NODE_NAME="${1:?Usage: $0 <nom_du_noeud> <fichier_csr>}"
CSR_FILE="${2:?Usage: $0 <nom_du_noeud> <fichier_csr>}"
CA_DIR="${CA_DIR:-/etc/mosquitto/master-ca}"
if [ ! -f "$CA_DIR/ca.key" ]; then
echo "CA introuvable dans $CA_DIR — lancer master-ca-init.sh d'abord." >&2
exit 1
fi
if [ ! -f "$CSR_FILE" ]; then
echo "CSR introuvable : $CSR_FILE" >&2
exit 1
fi
TMP_CERT="$(mktemp)"
trap 'rm -f "$TMP_CERT"' EXIT
openssl x509 -req -in "$CSR_FILE" \
-CA "$CA_DIR/ca.crt" -CAkey "$CA_DIR/ca.key" -CAcreateserial \
-out "$TMP_CERT" -days 825 -sha256 2>/dev/null
# Entitlement ACL pour ce noeud dans master-acl.conf (idempotent). Les
# règles globales non scopées (pattern write fail2ban/%u/ban, pattern
# read fail2ban/%u/action, topic read fail2ban/broadcast/action, cf.
# generic/mosquitto/master-acl.conf) suffisent pour la publication (%u),
# mais PAS pour la lecture du canal de diffusion : SUBSCRIBE sur
# fail2ban/broadcast/action reçoit bien un SUBACK positif, mais aucun
# message n'est jamais livré (constaté avec mosquitto_sub -v : SUBACK OK,
# zéro PUBLISH reçu). Seule une règle "topic read" explicite sous un bloc
# "user <nom>" dédié fait effectivement recevoir les messages (piège
# mosquitto : un SUBACK positif ne prouve pas qu'un SUBSCRIBE est
# autorisé, cf. CONTEXT.md).
ACL_FILE="${ACL_FILE:-/etc/mosquitto/master-acl.conf}"
if [ -f "$ACL_FILE" ]; then
if ! grep -q "^user $NODE_NAME\$" "$ACL_FILE"; then
echo "-> ajout de l'entitlement ACL pour '$NODE_NAME' dans $ACL_FILE" >&2
{
echo ""
echo "user $NODE_NAME"
echo "topic read fail2ban/broadcast/action"
echo "topic read fail2ban/broadcast/roster"
} >> "$ACL_FILE"
if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet mosquitto.service; then
systemctl restart mosquitto.service
fi
else
echo "-> entitlement ACL pour '$NODE_NAME' déjà présent dans $ACL_FILE, inchangé" >&2
fi
else
echo "-> ATTENTION : $ACL_FILE introuvable (pas sur le master ?) — pas d'entitlement ACL ajouté." >&2
echo " Le noeud '$NODE_NAME' ne recevra aucun SYNC_BAN tant que ce bloc n'est pas ajouté à la main :" >&2
echo " user $NODE_NAME" >&2
echo " topic read fail2ban/broadcast/action" >&2
echo " topic read fail2ban/broadcast/roster" >&2
fi
cat "$TMP_CERT"