Sondes Nagios¶
Cette section fournit des exemples de sondes (plugins) compatibles Nagios, Icinga, Centreon, Shinken, Naemon, et plus généralement tout outil qui comprend les codes retour Nagios :
Code |
État |
Signification |
|---|---|---|
0 |
OK |
Tout va bien |
1 |
WARNING |
Dégradé, à traiter |
2 |
CRITICAL |
Service KO, intervention requise |
3 |
UNKNOWN |
La sonde n’a pas pu s’exécuter |
Ces scripts sont des exemples : adaptez les noms (reemo_ =
INSTANCE_NAME), les ports et les seuils à votre plateforme, puis
validez-les en recette avant la mise en production.
Prérequis et installation¶
Les sondes qui interrogent Docker (Swarm, services, Vault, base de données) s’exécutent localement sur un manager de chaque cluster, via NRPE (ou via l’agent de votre outil). Les sondes réseau (certificats, HTTP, TURN, port de l’API) s’exécutent depuis le serveur de supervision.
Copier les scripts dans
/usr/local/lib/nagios/plugins/(droits0755, propriétaireroot).Autoriser l’utilisateur
nagiosà lancer uniquement ces scripts avecsudo, sans mot de passe. Évitez d’ajouternagiosau groupedocker: cela revient à lui donner les droits root.# /etc/sudoers.d/nagios-reemo (éditer avec visudo -f) nagios ALL=(root) NOPASSWD: /usr/local/lib/nagios/plugins/check_reemo_*
Dépendances :
bash,openssl,curl,awk,timeout(coreutils), etturnutils_uclient(paquetcoturn-utilsoucoturn) pour la sonde TURN.
check_reemo_swarm_nodes¶
À exécuter sur un manager de chaque cluster. Vérifie que tous les nœuds sont
Ready / Active, qu’aucun manager n’est injoignable et qu’un leader existe.
#!/bin/bash
# check_reemo_swarm_nodes - etat des noeuds Docker Swarm
out=$(docker node ls --format '{{.Hostname}} {{.Status}} {{.Availability}} {{.ManagerStatus}}' 2>&1)
if [ $? -ne 0 ]; then
echo "UNKNOWN - docker node ls : $out"; exit 3
fi
total=$(echo "$out" | wc -l)
bad=$(echo "$out" | awk '$2 != "Ready" || $3 != "Active" || $4 == "Unreachable"')
if [ -n "$bad" ]; then
echo "CRITICAL - noeud(s) en defaut : $(echo "$bad" | paste -sd ';') | nodes=$total"
exit 2
fi
if ! echo "$out" | grep -q 'Leader'; then
echo "CRITICAL - aucun leader Swarm | nodes=$total"; exit 2
fi
echo "OK - $total noeud(s) Ready/Active | nodes=$total"
exit 0
check_reemo_swarm_services¶
À exécuter sur un manager de chaque cluster. Vérifie pour chaque service que
le nombre de réplicas en cours correspond au nombre attendu, et signale les
mises à jour en échec (paused ou rollback).
#!/bin/bash
# check_reemo_swarm_services [PREFIXE] [REGEX_EXCLUSION]
# PREFIXE : ne controle que les services commencant par ce prefixe
# (ex. reemo_). Le service traefik est toujours controle.
# REGEX_EXCLUSION : services a ignorer. Par defaut : l'ancien systeme de
# sauvegarde (_mysqlbackup).
# Les taches uniques (restart_config: condition none, ex. _db et _logapidb) ne
# sont pas controlees sur leurs replicas, mais sur l'etat de leur derniere execution.
PREFIX="${1:-}"
EXCLUDE="${2:-_mysqlbackup$}"
list=$(docker service ls --format '{{.Name}} {{.Replicas}}' 2>&1)
if [ $? -ne 0 ]; then
echo "UNKNOWN - docker service ls : $list"; exit 3
fi
crit=(); warn=(); n=0
while read -r name rep _; do
[ -z "$name" ] && continue
if [ -n "$PREFIX" ] && [[ "$name" != "$PREFIX"* ]] && [ "$name" != "traefik" ]; then
continue
fi
[[ "$name" =~ $EXCLUDE ]] && continue
n=$((n + 1))
cond=$(docker service inspect "$name" --format '{{.Spec.TaskTemplate.RestartPolicy.Condition}}' 2>/dev/null)
if [ "$cond" = "none" ]; then
last=$(docker service ps "$name" --format '{{.CurrentState}}' 2>/dev/null | head -1)
case "$last" in
Complete*|Running*|Starting*|Preparing*|Assigned*|Pending*) ;;
*) warn+=("$name tache unique : ${last:-inconnue}") ;;
esac
continue
fi
cur=${rep%%/*}; want=${rep#*/}
[ "$cur" != "$want" ] && crit+=("$name $cur/$want")
st=$(docker service inspect "$name" --format '{{if .UpdateStatus}}{{.UpdateStatus.State}}{{end}}' 2>/dev/null)
case "$st" in
paused|rollback_started|rollback_paused|rollback_completed) warn+=("$name update=$st") ;;
esac
done <<< "$list"
if [ ${#crit[@]} -gt 0 ]; then
echo "CRITICAL - replicas manquants : $(IFS=';'; echo "${crit[*]}") $( [ ${#warn[@]} -gt 0 ] && IFS=';' && echo "/ ${warn[*]}") | services=$n"
exit 2
fi
if [ ${#warn[@]} -gt 0 ]; then
echo "WARNING - $(IFS=';'; echo "${warn[*]}") | services=$n"
exit 1
fi
echo "OK - $n service(s) avec tous leurs replicas | services=$n"
exit 0
check_reemo_cert¶
À exécuter depuis le serveur de supervision. Contrôle l’expiration, la chaîne de certification et le nom d’un certificat TLS. Fonctionne aussi sur les ports en TCP passthrough (Workstation, Appliance portal…) et sur les ports mTLS : le certificat serveur est lu avant que le certificat client ne soit demandé.
#!/bin/bash
# check_reemo_cert HOTE PORT [SNI] [WARN_JOURS] [CRIT_JOURS] [VERIF_CHAINE 1|0]
H="$1"; P="$2"; SNI="${3:-$1}"; W="${4:-30}"; C="${5:-7}"; VERIFY="${6:-1}"
if [ -z "$H" ] || [ -z "$P" ]; then
echo "UNKNOWN - usage : $0 HOTE PORT [SNI] [WARN] [CRIT] [VERIF_CHAINE]"; exit 3
fi
out=$(echo | timeout 15 openssl s_client -connect "$H:$P" -servername "$SNI" \
-verify_hostname "$SNI" 2>&1)
end=$(echo "$out" | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -z "$end" ]; then
echo "CRITICAL - impossible de lire le certificat sur $H:$P"; exit 2
fi
subject=$(echo "$out" | openssl x509 -noout -subject 2>/dev/null | sed 's/^subject=//')
days=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))
vcode=$(echo "$out" | grep -o 'Verify return code: [0-9]*' | head -1 | awk '{print $4}')
vmsg=$(echo "$out" | grep 'Verify return code' | head -1 | sed 's/.*(\(.*\))/\1/')
if [ "$days" -lt 0 ]; then
echo "CRITICAL - certificat EXPIRE depuis $(( -days )) j ($subject) | days=$days"; exit 2
fi
if [ "$VERIFY" = "1" ] && [ "$vcode" != "0" ]; then
echo "CRITICAL - chaine/nom invalide : $vmsg ($subject), expire dans $days j | days=$days"; exit 2
fi
if [ "$days" -le "$C" ]; then
echo "CRITICAL - expire dans $days j le $end ($subject) | days=$days"; exit 2
fi
if [ "$days" -le "$W" ]; then
echo "WARNING - expire dans $days j le $end ($subject) | days=$days"; exit 1
fi
echo "OK - expire dans $days j le $end ($subject) | days=$days"
exit 0
Astuce
Pour les certificats émis par la PKI interne (API, relayws, provisionnement),
passez VERIF_CHAINE=0 : la CA interne n’est pas connue du serveur de
supervision. Seule l’expiration est alors contrôlée.
Healthchecks HTTP (plugin standard check_http)¶
Le plugin check_http (ou check_curl) du paquet monitoring-plugins
suffit pour le portail d’administration et signal. Pour le portail, le script
reemo_healthcheck (voir Santé et monitoring) contrôle en plus le statut de
chaque sous-service :
# Portail : utilisez de préférence le script reemo_healthcheck, qui analyse le JSON
reemo_healthcheck https://portail.example.com
# Portail d'administration
check_http -H admin.example.com -S --sni -u /api/healthcheck -e 200 -w 3 -c 10
# Signal (port signal, 8443 par defaut)
# (reponse attendue : HTTP 426 avec le texte "Upgrade Required")
check_http -H signal.example.com -p 8443 -S --sni -u / -e 426 -s 'Upgrade Required' -w 3 -c 10
# Redirection HTTP -> HTTPS du portail
check_http -H portail.example.com -p 80 -e 301,302,307,308
check_reemo_api_port¶
À exécuter depuis le serveur de supervision, sans certificat. Réservé à
l’architecture séparée api_manager / portal_manager. Vérifie que le port
443 de l’API répond et que l’API exige un certificat client : la connexion
sans certificat doit être refusée au niveau TLS.
#!/bin/bash
# check_reemo_api_port API_IP [PORT]
IP="$1"; PORT="${2:-443}"
[ -z "$IP" ] && { echo "UNKNOWN - usage : $0 API_IP [PORT]"; exit 3; }
err=$(curl -sSk -o /dev/null -w '%{http_code}' --max-time 15 "https://$IP:$PORT/" 2>&1)
rc=$?
case $rc in
0)
echo "CRITICAL - API $IP:$PORT repond HTTP ${err: -3} SANS certificat client : mTLS non exige"
exit 2 ;;
6|7)
echo "CRITICAL - API $IP:$PORT : connexion impossible (port ferme ou filtre)"; exit 2 ;;
28)
echo "CRITICAL - API $IP:$PORT : timeout"; exit 2 ;;
esac
if echo "$err" | grep -qi -E 'certificate required|bad certificate|certificate_required'; then
echo "OK - API $IP:$PORT ouvert, certificat client exige (mTLS)"; exit 0
fi
echo "WARNING - API $IP:$PORT : reponse TLS inattendue (curl $rc) : $(echo "$err" | head -1)"
exit 1
Note
Le message renvoyé par curl dépend de la version de TLS et de la
bibliothèque TLS utilisée (tlsv13 alert certificate required en TLS 1.3
avec OpenSSL, alert bad certificate en TLS 1.2). Validez la sonde sur votre
plateforme et adaptez l’expression recherchée si besoin.
check_reemo_turn¶
À exécuter depuis le serveur de supervision (idéalement depuis l’extérieur, comme
un client). Fait une allocation TURN réelle avec des identifiants éphémères
(TURN_AUTH_MODE=secret).
#!/bin/bash
# check_reemo_turn HOTE [PORT] [FICHIER_SECRET]
# FICHIER_SECRET : fichier contenant TURN_SECRET (droits 0400, proprietaire nagios)
H="$1"; P="${2:-58200}"; F="${3:-/etc/nagios/reemo_turn_secret}"
if [ -z "$H" ] || [ ! -r "$F" ]; then
echo "UNKNOWN - usage : $0 HOTE [PORT] [FICHIER_SECRET] (secret lisible requis)"; exit 3
fi
command -v turnutils_uclient >/dev/null || { echo "UNKNOWN - turnutils_uclient absent"; exit 3; }
u="$(( $(date +%s) + 600 )):nagios"
p=$(printf '%s' "$u" | openssl dgst -sha1 -hmac "$(tr -d '\n' < "$F")" -binary | base64)
out=$(timeout 30 turnutils_uclient -y -n 5 -m 1 -u "$u" -w "$p" -p "$P" "$H" 2>&1)
recv=$(echo "$out" | grep -o 'tot_recv_msgs=[0-9]*' | tail -1 | cut -d= -f2)
if echo "$out" | grep -qi '401\|unauthorized\|wrong credentials'; then
echo "CRITICAL - TURN $H:$P : authentification refusee (secret different ?)"; exit 2
fi
if [ -n "$recv" ] && [ "$recv" -gt 0 ]; then
echo "OK - TURN $H:$P allocation et relais OK ($recv msg recus) | recv=$recv"; exit 0
fi
echo "CRITICAL - TURN $H:$P : aucune allocation/relais ($(echo "$out" | tail -1))"
exit 2
Note
Le format de sortie de turnutils_uclient peut varier selon la version de
coturn : validez l’analyse (tot_recv_msgs) sur votre version. En mode
TURN_AUTH_MODE=static, remplacez -u/-w par TURN_USERNAME /
TURN_PASSWORD.
Avertissement
TURN_SECRET permet de générer des identifiants TURN valides. Stockez-le
avec des droits restreints (chmod 0400, propriétaire nagios).
check_reemo_vault¶
À exécuter sur chaque nœud du cluster qui héberge Vault. La sonde contrôle
les réplicas présents sur le nœud local. Codes retour de bao status :
0 = déverrouillé, 2 = verrouillé (sealed), 1 = erreur.
#!/bin/bash
# check_reemo_vault [PREFIXE_SERVICE]
PREFIX="${1:-reemo_vault}"
cids=$(docker ps --format '{{.ID}} {{.Names}}' | awk -v p="^${PREFIX}[0-9]+\\\\." '$2 ~ p {print $1":"$2}')
if [ -z "$cids" ]; then
echo "OK - aucune replica Vault sur ce noeud"; exit 0
fi
sealed=(); err=(); ok=0
for c in $cids; do
id=${c%%:*}; name=${c#*:}; name=${name%%.*}
docker exec "$id" bao status >/dev/null 2>&1
case $? in
0) ok=$((ok + 1));;
2) sealed+=("$name");;
*) err+=("$name");;
esac
done
if [ ${#sealed[@]} -gt 0 ]; then
echo "CRITICAL - Vault SEALED : ${sealed[*]}"; exit 2
fi
if [ ${#err[@]} -gt 0 ]; then
echo "CRITICAL - Vault en erreur : ${err[*]}"; exit 2
fi
echo "OK - $ok replica(s) Vault deverrouillee(s)"
exit 0
check_reemo_mariadb¶
À exécuter sur les nœuds infra_manager / api_manager. Seul le nœud qui
héberge la base répond : sur les autres nœuds, la sonde renvoie OK. L’état
global du service est couvert par check_reemo_swarm_services.
#!/bin/bash
# check_reemo_mariadb [NOM_SERVICE]
SVC="${1:-reemo_mysql}"
id=$(docker ps -q --filter "name=^${SVC}\." | head -1)
if [ -z "$id" ]; then
echo "OK - $SVC non heberge sur ce noeud"; exit 0
fi
out=$(docker exec "$id" sh -c 'MYSQL_PWD=$(cat "$MYSQL_ROOT_PASSWORD_FILE") mysqladmin -u root status' 2>&1)
if [ $? -ne 0 ]; then
echo "CRITICAL - $SVC : $out"; exit 2
fi
threads=$(echo "$out" | grep -o 'Threads: [0-9]*' | awk '{print $2}')
echo "OK - $SVC : $out | threads=${threads:-0}"
exit 0
check_reemo_ndb¶
À exécuter sur un nœud qui héberge un mgmd (DB_DIALECT=NDBCLUSTER).
Vérifie que tous les nœuds NDB sont connectés et contrôle l’occupation mémoire.
#!/bin/bash
# check_reemo_ndb [WARN_%] [CRIT_%]
W="${1:-80}"; C="${2:-90}"
id=$(docker ps -q --filter "name=reemo_mysql-mgmd" | head -1)
[ -z "$id" ] && { echo "UNKNOWN - aucun mgmd sur ce noeud"; exit 3; }
show=$(docker exec "$id" ndb_mgm -e show 2>&1) || { echo "CRITICAL - ndb_mgm : $show"; exit 2; }
nc=$(echo "$show" | grep -c 'not connected')
if [ "$nc" -gt 0 ]; then
echo "CRITICAL - $nc noeud(s) NDB non connecte(s) : $(echo "$show" | grep 'not connected' | awk '{print $1}' | paste -sd ' ')"
exit 2
fi
mem=$(docker exec "$id" ndb_mgm -e "all report memory" 2>/dev/null \
| grep -o '[A-Za-z]* usage is [0-9]*%' | awk '{gsub("%","",$4); print $1"="$4}')
max=$(echo "$mem" | cut -d= -f2 | sort -n | tail -1)
perf=$(echo "$mem" | sort -u | paste -sd ' ')
if [ -n "$max" ] && [ "$max" -ge "$C" ]; then
echo "CRITICAL - memoire NDB a ${max}% | $perf"; exit 2
fi
if [ -n "$max" ] && [ "$max" -ge "$W" ]; then
echo "WARNING - memoire NDB a ${max}% | $perf"; exit 1
fi
echo "OK - tous les noeuds NDB connectes, memoire max ${max:-?}% | $perf"
exit 0
check_reemo_pki¶
À exécuter sur le poste d’administration Ansible (là où se trouve la PKI :
LOCAL_PATH ou clone du dépôt git de la PKI). Contrôle l’expiration de tous
les certificats de la PKI interne.
#!/bin/bash
# check_reemo_pki REPERTOIRE [WARN_JOURS] [CRIT_JOURS]
D="$1"; W="${2:-30}"; C="${3:-7}"
[ -d "$D" ] || { echo "UNKNOWN - repertoire $D introuvable"; exit 3; }
crit=(); warn=(); n=0
for f in "$D"/*.crt; do
[ -e "$f" ] || continue
n=$((n + 1))
end=$(openssl x509 -in "$f" -noout -enddate 2>/dev/null | cut -d= -f2) || continue
days=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))
if [ "$days" -le "$C" ]; then crit+=("$(basename "$f")=${days}j")
elif [ "$days" -le "$W" ]; then warn+=("$(basename "$f")=${days}j")
fi
done
[ ${#crit[@]} -gt 0 ] && { echo "CRITICAL - ${crit[*]} ${warn[*]}"; exit 2; }
[ ${#warn[@]} -gt 0 ] && { echo "WARNING - ${warn[*]}"; exit 1; }
echo "OK - $n certificat(s) valides plus de $W jours"
exit 0
check_reemo_backup_age¶
La sauvegarde (service reemo_backup) envoie ses archives vers le serveur de
sauvegarde. Le contrôle le plus fiable consiste à vérifier sur le serveur de
sauvegarde l’âge du fichier le plus récent :
#!/bin/bash
# check_reemo_backup_age REPERTOIRE_BACKUP [WARN_SEC] [CRIT_SEC]
D="$1"; W="${2:-90000}"; C="${3:-172800}" # 25 h / 48 h
last=$(ls -1t "$D" 2>/dev/null | head -1)
[ -z "$last" ] && { echo "CRITICAL - aucune sauvegarde dans $D"; exit 2; }
exec /usr/lib/nagios/plugins/check_file_age -w "$W" -c "$C" -f "$D/$last"
En complément, activez les notifications natives du conteneur de sauvegarde en
cas d’échec : BACKUP_MAIL_RECEIVER ou BACKUP_WEBHOOK_ENABLED /
BACKUP_WEBHOOK_URL, avec BACKUP_NOTIFY_ON.
Configuration NRPE¶
Exemple de /etc/nagios/nrpe.d/reemo.cfg sur un manager portal_manager :
command[check_reemo_swarm_nodes]=/usr/bin/sudo /usr/local/lib/nagios/plugins/check_reemo_swarm_nodes
command[check_reemo_swarm_services]=/usr/bin/sudo /usr/local/lib/nagios/plugins/check_reemo_swarm_services reemo_
command[check_docker]=/usr/lib/nagios/plugins/check_procs -c 1: -C dockerd
command[check_disk_docker]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p /var/lib/docker
command[check_disk_opt]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p /opt
Sur un manager api_manager / infra_manager, ajoutez :
command[check_reemo_vault]=/usr/bin/sudo /usr/local/lib/nagios/plugins/check_reemo_vault
command[check_reemo_mariadb]=/usr/bin/sudo /usr/local/lib/nagios/plugins/check_reemo_mariadb
# ou, en NDB Cluster :
command[check_reemo_ndb]=/usr/bin/sudo /usr/local/lib/nagios/plugins/check_reemo_ndb 80 90
Définitions Nagios¶
Exemple de commandes et de services côté serveur Nagios :
define command {
command_name check_reemo_cert
command_line $USER1$/check_reemo_cert $ARG1$ $ARG2$ $ARG3$ 30 7 $ARG4$
}
define command {
command_name check_reemo_https
command_line $USER1$/check_http -H $ARG1$ -p $ARG2$ -S --sni -u $ARG3$ -e 200 -w 3 -c 10
}
define command {
command_name check_reemo_tcp
command_line $USER1$/check_tcp -H $ARG1$ -p $ARG2$ -w 2 -c 5
}
define command {
command_name check_reemo_signal
command_line $USER1$/check_http -H $ARG1$ -p $ARG2$ -S --sni -u / -e 426 -s 'Upgrade Required' -w 3 -c 10
}
define command {
command_name check_reemo_api_port
command_line $USER1$/check_reemo_api_port $ARG1$ 443
}
define command {
command_name check_reemo_turn
command_line $USER1$/check_reemo_turn $ARG1$ $ARG2$ /etc/nagios/reemo_turn_secret
}
# --- Portail -------------------------------------------------------------
# La commande reemo_healthcheck est définie dans la page « Santé et monitoring »
define service {
use generic-service
host_name portail
service_description Reemo - certificat portail
check_command check_reemo_cert!portail.example.com!443!portail.example.com!1
check_interval 720
}
define service {
use generic-service
host_name portail
service_description Reemo - healthcheck portail
check_command reemo_healthcheck!https://portail.example.com
}
define service {
use generic-service
host_name portail
service_description Reemo - signal
check_command check_reemo_signal!signal.example.com!8443
}
define service {
use generic-service
host_name portail
service_description Reemo - certificat workstation
check_command check_reemo_cert!portail.example.com!8445!portail.example.com!0
check_interval 720
}
define service {
use generic-service
host_name portail
service_description Reemo - services swarm
check_command check_nrpe!check_reemo_swarm_services
}
# --- Appliances (APPLIANCE_ENABLED) --------------------------------------
define service {
use generic-service
host_name portail
service_description Reemo - port appliance portal 8444
check_command check_reemo_tcp!portail.example.com!8444
}
define service {
use generic-service
host_name portail
service_description Reemo - certificat appliance portal
check_command check_reemo_cert!portail.example.com!8444!portail.example.com!0
check_interval 720
}
# --- Credential portal (CREDENTIAL_ENABLED + CREDENTIALPORTAL_ENABLED) ---
define service {
use generic-service
host_name portail
service_description Reemo - port credential portal 8446
check_command check_reemo_tcp!portail.example.com!8446
}
define service {
use generic-service
host_name portail
service_description Reemo - certificat credential portal
check_command check_reemo_cert!portail.example.com!8446!portail.example.com!0
check_interval 720
}
# --- API (architecture separee) ------------------------------------------
define service {
use generic-service
host_name api
service_description Reemo - API port 443 / mTLS exige
check_command check_reemo_api_port!10.0.0.10
}
define service {
use generic-service
host_name api
service_description Reemo - certificat API
check_command check_reemo_cert!10.0.0.10!443!reemo_api!0
check_interval 720
}
define service {
use generic-service
host_name api
service_description Reemo - Vault sealed
check_command check_nrpe!check_reemo_vault
}
# --- TURN ----------------------------------------------------------------
define service {
use generic-service
host_name turn
service_description Reemo - TURN allocation
check_command check_reemo_turn!203.0.113.10!58200
}
Fréquences conseillées :
healthchecks, services Swarm, TURN, Vault, API : toutes les 1 à 5 minutes ;
certificats et PKI : 2 fois par jour (
check_interval 720) ;sauvegardes : toutes les heures.