#!/bin/bash # # 20260308 - # ajout de l'autoupdate # ajout du support ntfy.sh (prioritaire sur le mail) # --- CONFIGURATION --- THRESHOLD=80 LOAD_THRESHOLD=5.0 PROC_THRESHOLD=500 TMP_THRESHOLD=90 CONN_THRESHOLD=500 HOST=$(hostname) SCRIPT_PATH="$0" SCRIPT_NAME=$(basename "$SCRIPT_PATH") # --- CHARGEMENT DE LA CONFIGURATION (Style msmtp) --- # On cherche d'abord dans le home de l'utilisateur, puis au niveau système CONF_USER="$HOME/.sys_check.conf" CONF_SYSTEM="/etc/sys_check.conf" if [ -f "$CONF_USER" ]; then source "$CONF_USER" elif [ -f "$CONF_SYSTEM" ]; then source "$CONF_SYSTEM" fi # Initialisation des variables de notification si non définies dans les fichiers de conf DEST="${DEST:-root}" NTFY_SERVER="${NTFY_SERVER}" NTFY_TOPIC="${NTFY_TOPIC}" NTFY_TOKEN="${NTFY_TOKEN}" REPORT="" ALERT=false # Fonction pour ajouter une ligne au rapport avec une icône add_to_report() { REPORT="${REPORT}$1\n" } # --- Configuration de l'auto-update --- BASE_URL="https://git.abonnel.fr/cedricAbonnel/scripts-bash/raw/branch/main/servers/linux" URL_SCRIPT="${BASE_URL}/${SCRIPT_NAME}" URL_HASH="${URL_SCRIPT}.sha256" # On suppose qu'un fichier .sha256 existe TMP_FILE="/tmp/${SCRIPT_NAME}.new" # --- Fonction de mise à jour --- update_script() { # 1. Récupérer le hash distant avec timeout REMOTE_HASH=$(curl -s -f --connect-timeout 3 --max-time 5 "$URL_HASH" | awk '{print $1}') # Si on n'arrive pas à lire le hash distant, on ignore l'update [[ -z "$REMOTE_HASH" ]] && return 1 # 2. Calculer le hash local LOCAL_HASH=$(sha256sum "$SCRIPT_PATH" | awk '{print $1}') # 3. Comparaison if [ "$LOCAL_HASH" != "$REMOTE_HASH" ]; then echo "[Update] Nouvelle version détectée..." # 4. Téléchargement du nouveau script if curl -s -f --connect-timeout 5 --max-time 10 "$URL_SCRIPT" -o "$TMP_FILE"; then # 5. Vérification du hash du fichier téléchargé (Sécurité) DOWNLOADED_HASH=$(sha256sum "$TMP_FILE" | awk '{print $1}') if [ "$DOWNLOADED_HASH" == "$REMOTE_HASH" ]; then mv "$TMP_FILE" "$SCRIPT_PATH" chmod +x "$SCRIPT_PATH" echo "[Update] Mise à jour appliquée. Relance..." exec "$SCRIPT_PATH" "$@" else echo "[Error] Hash corrompu après téléchargement." rm -f "$TMP_FILE" fi fi fi } # Lancer la vérification update_script "$@" # --- Reste du script --- echo "Exécution du script principal..." # 1. CHECK DISQUE & INODES DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//') INODE_USAGE=$(df -i / | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$DISK_USAGE" -gt "$THRESHOLD" ]; then add_to_report "⚠️ DISQUE : $DISK_USAGE% utilisé\n" ALERT=true fi if [ "$INODE_USAGE" -gt "$THRESHOLD" ]; then add_to_report "⚠️ INODES : $INODE_USAGE% utilisé\n" ALERT=true fi # --- CHECK RAM & SWAP --- RAM_USAGE=$(free | grep Mem | awk '{print int($3/$2 * 100)}') # On ajoute '|| echo 0' pour s'assurer que la variable n'est jamais vide SWAP_TOTAL=$(free | grep Swap | awk '{print $2}' | grep -E '^[0-9]+$' || echo 0) if [ "$RAM_USAGE" -gt "$THRESHOLD" ]; then add_to_report "⚠️ RAM : $RAM_USAGE% utilisé\n" ALERT=true fi # On vérifie si SWAP_TOTAL est supérieur à 0 et n'est pas vide if [ -n "$SWAP_TOTAL" ] && [ "$SWAP_TOTAL" -gt 0 ]; then # Calcul du SWAP_USAGE avec une sécurité pour éviter la division par zéro SWAP_USAGE=$(free | grep Swap | awk '{print ($2>0) ? int($3/$2 * 100) : 0}') if [ "$SWAP_USAGE" -gt 50 ]; then add_to_report "⚠️ SWAP : $SWAP_USAGE% utilisé (Saturation RAM imminente)\n" ALERT=true fi fi add_to_report "---" # 3. CHECK CHARGE CPU CPU_LOAD=$(uptime | awk -F'load average:' '{ print $2 }' | cut -d',' -f1 | tr -d ' ' | tr ',' '.') if (( $(echo "$CPU_LOAD > $LOAD_THRESHOLD" | bc -l) )); then add_to_report "🔥 CPU LOAD : $CPU_LOAD (Surcharge)\n" ALERT=true fi # 4. CHECK SERVICES (SSH et Fail2Ban sont vitaux) for SVC in "ssh" "fail2ban"; do if ! systemctl is-active --quiet "$SVC"; then add_to_report "❌ SERVICE : $SVC est ARRÊTÉ\n" ALERT=true fi done add_to_report "---" # ------------------------------------------------ # 5. NOMBRE DE PROCESSUS # ------------------------------------------------ PROC_COUNT=$(ps -e --no-headers | wc -l) if [ "$PROC_COUNT" -gt "$PROC_THRESHOLD" ]; then add_to_report "PROCESSUS : $PROC_COUNT processus actifs\n" ALERT=true fi add_to_report "---" # ------------------------------------------------ # 6. ESPACE /tmp # ------------------------------------------------ TMP_USAGE=$(df /tmp | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$TMP_USAGE" -gt "$TMP_THRESHOLD" ]; then add_to_report "/tmp : $TMP_USAGE% utilisé\n" ALERT=true fi add_to_report "---" # ------------------------------------------------ # 7. PROCESSUS ZOMBIES # ------------------------------------------------ ZOMBIES=$(ps aux | awk '{ if ($8=="Z") print $0 }' | wc -l) if [ "$ZOMBIES" -gt 0 ]; then add_to_report "ZOMBIES : $ZOMBIES processus zombies\n" ALERT=true fi # ------------------------------------------------ # 8. FICHIERS SUPPRIMÉS MAIS OUVERTS (Filtré) # ------------------------------------------------ # On récupère les données, puis on exclut les processus du script lui-même # On exclut aussi souvent 'systemd-j' (journal) car il gère ses propres rotations DELETED_DATA=$(sudo lsof +L1 2>/dev/null | tail -n +2 | grep -Ev "grep|lsof|tail|cron|sh|systemd-j|sys_check") # On compte proprement les lignes DELETED_COUNT=$(echo "$DELETED_DATA" | grep -v '^$' | wc -l) if (( DELETED_COUNT > 0 )); then # On extrait les noms des commandes uniques pour le rapport PROCESS_NAMES=$(echo "$DELETED_DATA" | awk '{print $1}' | sort -u | xargs) add_to_report "📂 FICHIERS SUPPRIMÉS MAIS OUVERTS : $DELETED_COUNT (Processus : $PROCESS_NAMES)" ALERT=true fi add_to_report "---" # ------------------------------------------------ # 9. CONNEXIONS RÉSEAU # ------------------------------------------------ CONN_COUNT=$(ss -tun | tail -n +2 | wc -l) if [ "$CONN_COUNT" -gt "$CONN_THRESHOLD" ]; then add_to_report "CONNEXIONS RÉSEAU : $CONN_COUNT\n" ALERT=true fi add_to_report "---" # ------------------------------------------------ # 10. ERREURS CRITIQUES (Dernière heure) # ------------------------------------------------ # On filtre par priorité 3 (Error) ou moins, depuis 1 heure LOG_CONTENT=$(journalctl -p 3 --since "1 hour ago" --no-pager --quiet) # On compte le nombre de lignes réelles LOG_COUNT=$(echo "$LOG_CONTENT" | grep -v '^--' | grep -v '^$' | wc -l) if (( LOG_COUNT > 0 )); then add_to_report "📑 ERREURS CRITIQUES (Dernière heure : $LOG_COUNT) :" add_to_report "$(echo "$LOG_CONTENT" | tail -n 15 | sed 's/^/ /')" ALERT=true fi add_to_report "---" # ------------------------------------------------ # --- ENVOI DE L'ALERTE --- # ------------------------------------------------ if [ "$ALERT" = true ]; then SUBJECT="🔴 ALERTE SERVEUR [$HOST] - $(date +'%H:%M')" if [ -z "$NTFY_TOPIC" ]; then # Construction du corps du mail avec un header propre MAIL_BODY="Bonjour,\n\nUne ou plusieurs anomalies ont été détectées sur le serveur : $HOST\n" MAIL_BODY="$MAIL_BODY\n------------------------------------------------\n" MAIL_BODY="$MAIL_BODY$REPORT" MAIL_BODY="$MAIL_BODY\n------------------------------------------------\n" MAIL_BODY="$MAIL_BODY\nDate du rapport : $(date)" echo -e "$MAIL_BODY" | mail -s "$SUBJECT" "$DEST" else # Mode NTFY AUTH_OPT=() [ -n "$NTFY_TOKEN" ] && AUTH_OPT=(-H "Authorization: Bearer $NTFY_TOKEN") # Nettoyage du rapport pour le format push CLEAN_REPORT=$(echo -e "$REPORT" | sed '/^---$/d') curl -s "${AUTH_OPT[@]}" \ -H "Title: $SUBJECT" \ -H "Priority: high" \ -H "Tags: warning,server" \ -d "$CLEAN_REPORT" \ "$NTFY_SERVER/$NTFY_TOPIC" > /dev/null fi fi