216 lines
6.9 KiB
Bash
216 lines
6.9 KiB
Bash
#!/bin/bash
|
|
|
|
# --- 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")
|
|
|
|
# On envoie à 'root', le système fera la redirection grâce aux aliases
|
|
DEST="root"
|
|
|
|
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
|
|
|
|
# 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
|
|
|
|
# ------------------------------------------------
|
|
# 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
|
|
|
|
# ------------------------------------------------
|
|
# 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
|
|
|
|
# ------------------------------------------------
|
|
# 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
|
|
|
|
|
|
|
|
# ------------------------------------------------
|
|
# 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
|
|
|
|
|
|
# ------------------------------------------------
|
|
# 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
|
|
|
|
|
|
# ------------------------------------------------
|
|
# ENVOI MAIL
|
|
# ------------------------------------------------
|
|
if [ "$ALERT" = true ]; then
|
|
SUBJECT="🔴 ALERTE SERVEUR [$HOST] - $(date +'%H:%M')"
|
|
|
|
# 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"
|
|
fi |