#!/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 # É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 }" CSR_FILE="${2:?Usage: $0 }" 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 " 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"