From 047da772aa1a226b59e1fd9a38df68d56a741ed2 Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 2 Jan 2026 10:40:25 +0000 Subject: [PATCH] Actualiser system_hardening_optimized.sh --- system_hardening_optimized.sh | 1579 +++++++++++++-------------------- 1 file changed, 597 insertions(+), 982 deletions(-) diff --git a/system_hardening_optimized.sh b/system_hardening_optimized.sh index 4ce5fe2..1832175 100644 --- a/system_hardening_optimized.sh +++ b/system_hardening_optimized.sh @@ -2,11 +2,11 @@ ################################################################################ # Script: system_hardening_optimized.sh -# Version: 8.0 +# Version: 7.0 # Date: $(date +%Y-%m-%d) # Author: Security Team # Description: Système de durcissement sécurité pour Debian/Ubuntu LTS -# avec détection automatique des ports et contrôle des étapes +# avec détection automatique des ports ouverts # License: GPLv3 ################################################################################ @@ -26,14 +26,6 @@ readonly OPEN_PORTS_FILE="/tmp/open_ports_detected.txt" TOTAL_STEPS=31 CURRENT_STEP=1 -# Variables de contrôle -FORCE_ALL=false -FORCE_STEPS=() -SKIP_STEPS=() -RESET_ALL=false -LIST_STEPS=false -SHOW_STATUS=false - # ============================================================================== # COULEURS # ============================================================================== @@ -46,44 +38,6 @@ readonly BLUE='\033[0;34m' readonly MAGENTA='\033[0;35m' readonly NC='\033[0m' -# ============================================================================== -# DÉFINITION DES ÉTAPES -# ============================================================================== - -declare -A STEP_DESCRIPTIONS=( - ["install_security_tools"]="Installation des outils de sécurité" - ["detect_open_ports"]="Détection des ports ouverts" - ["configure_process_accounting"]="Configuration Process Accounting" - ["configure_sysctl_security"]="Durcissement sysctl" - ["configure_log_permissions"]="Permissions des logs" - ["configure_pam_password_policy"]="Politique mots de passe PAM" - ["configure_login_defs"]="Configuration login.defs" - ["configure_umask"]="Configuration umask" - ["configure_aide_sha512"]="Configuration AIDE SHA512" - ["initialize_aide_db"]="Initialisation base AIDE" - ["configure_clamav"]="Configuration ClamAV" - ["configure_chrony"]="Configuration Chrony" - ["harden_ssh"]="Durcissement SSH" - ["configure_banners"]="Configuration bannières" - ["configure_firewall_ports"]="Configuration pare-feu UFW" - ["configure_fail2ban"]="Configuration Fail2ban" - ["remove_unneeded_packages"]="Suppression paquets inutiles" - ["restrict_file_permissions"]="Restriction permissions fichiers" - ["disable_risky_kernel_modules"]="Désactivation modules noyau" - ["configure_security_limits"]="Configuration limites sécurité" - ["verify_packages_integrity"]="Vérification intégrité paquets" - ["configure_automatic_updates"]="Configuration mises à jour auto" - ["configure_aide_cron"]="Configuration tâche AIDE cron" - ["harden_smtp_banner"]="Durcissement bannière SMTP" - ["harden_systemd_services"]="Durcissement services systemd" - ["configure_advanced_pam"]="Configuration PAM avancée" - ["check_partition_layout"]="Vérification partitions" - ["check_vmlinuz"]="Vérification fichiers noyau" - ["run_chkrootkit"]="Exécution chkrootkit" - ["prepare_ssh_cleanup"]="Préparation nettoyage SSH" - ["run_lynis_audit"]="Audit Lynis final" -) - # ============================================================================== # FONCTIONS UTILITAIRES # ============================================================================== @@ -123,46 +77,17 @@ print_info() { log_message "$1" "INFO" } -# ============================================================================== -# GESTION DES ÉTAPES -# ============================================================================== - check_step_done() { - local step_name="$1" - - if $FORCE_ALL; then - return 1 - fi - - if [[ " ${FORCE_STEPS[@]} " =~ " ${step_name} " ]]; then - print_info "Forçage de l'étape: $step_name" - return 1 - fi - - if [[ " ${SKIP_STEPS[@]} " =~ " ${step_name} " ]]; then - print_info "Saut de l'étape: $step_name" - return 0 - fi - - grep -q "^${step_name}$" "$STATUS_FILE" 2>/dev/null + grep -q "^${1}$" "$STATUS_FILE" 2>/dev/null } mark_step_done() { - local step_name="$1" - - if [[ " ${SKIP_STEPS[@]} " =~ " ${step_name} " ]]; then - print_info "Étape $step_name ignorée - non marquée comme terminée" - return 0 - fi - - sed -i "/^${step_name}$/d" "$STATUS_FILE" 2>/dev/null || true - echo "$step_name" >> "$STATUS_FILE" - log_message "Étape '$step_name' marquée comme terminée" "STATUS" + echo "$1" >> "$STATUS_FILE" + log_message "Étape '$1' marquée comme terminée" "STATUS" } skip_step() { - local step_name="$1" - print_info "Étape déjà effectuée : $step_name" + print_info "Étape déjà effectuée : $1" CURRENT_STEP=$((CURRENT_STEP + 1)) } @@ -206,382 +131,21 @@ update_config_value() { fi } -# ============================================================================== -# FONCTIONS DE CONTRÔLE -# ============================================================================== - -reset_step() { - local step_name="$1" - - if [[ -f "$STATUS_FILE" ]]; then - sed -i "/^${step_name}$/d" "$STATUS_FILE" 2>/dev/null || true - print_success "Étape '$step_name' réinitialisée" - - case $step_name in - "harden_ssh") - if [[ -f "${BACKUP_DIR}/sshd_config" ]]; then - read -p "Restaurer la configuration SSH originale ? (o/N): " -r restore_ssh - if [[ "$restore_ssh" =~ ^[Oo]$ ]]; then - cp "${BACKUP_DIR}/sshd_config" /etc/ssh/sshd_config - systemctl restart sshd 2>/dev/null || true - print_success "Configuration SSH restaurée" - fi - fi - ;; - "configure_firewall_ports") - if command -v ufw > /dev/null 2>&1; then - read -p "Réinitialiser les règles UFW ? (o/N): " -r reset_ufw - if [[ "$reset_ufw" =~ ^[Oo]$ ]]; then - ufw --force reset > /dev/null 2>&1 || true - print_success "Règles UFW réinitialisées" - fi - fi - ;; - "configure_fail2ban") - if [[ -f "${BACKUP_DIR}/jail.local" ]]; then - read -p "Restaurer la configuration Fail2ban originale ? (o/N): " -r restore_fail2ban - if [[ "$restore_fail2ban" =~ ^[Oo]$ ]]; then - cp "${BACKUP_DIR}/jail.local" /etc/fail2ban/jail.local 2>/dev/null || true - systemctl restart fail2ban 2>/dev/null || true - print_success "Configuration Fail2ban restaurée" - fi - fi - ;; - esac - else - print_warning "Fichier de statut non trouvé" - fi -} - -reset_all_steps() { - print_step "Réinitialisation de toutes les étapes" - - echo -e "${RED}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${RED}║ ⚠ ATTENTION CRITIQUE ⚠ ║${NC}" - echo -e "${RED}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" - echo "Cette action va:" - echo "1. Supprimer l'historique d'exécution de toutes les étapes" - echo "2. Permettre une ré-exécution complète du script" - echo "3. NE supprime PAS les configurations appliquées" - echo "" - echo -n "Confirmez-vous la réinitialisation complète ? (oui/NON): " - - read -r confirmation - - if [[ "$confirmation" == "oui" ]]; then - if [[ -f "$STATUS_FILE" ]]; then - cp "$STATUS_FILE" "${STATUS_FILE}.backup.$(date +%Y%m%d_%H%M%S)" - print_info "Ancien statut sauvegardé" - fi - - > "$STATUS_FILE" - print_success "Toutes les étapes ont été réinitialisées" - print_info "Vous pouvez maintenant ré-exécuter le script" - - echo "" - read -p "Voulez-vous restaurer les configurations originales ? (o/N): " -r restore_all - - if [[ "$restore_all" =~ ^[Oo]$ ]]; then - echo "" - echo "Sélectionnez les configurations à restaurer:" - echo "1) SSH" - echo "2) UFW (pare-feu)" - echo "3) Fail2ban" - echo "4) Toutes les configurations" - echo "5) Aucune" - echo "" - read -p "Choix (1-5): " -r restore_choice - - case $restore_choice in - 1) - restore_ssh_config - ;; - 2) - restore_ufw_config - ;; - 3) - restore_fail2ban_config - ;; - 4) - restore_all_configs - ;; - *) - print_info "Aucune restauration effectuée" - ;; - esac - fi - else - print_error "Réinitialisation annulée" - exit 1 - fi -} - -restore_ssh_config() { - if [[ -f "${BACKUP_DIR}/sshd_config" ]]; then - cp "${BACKUP_DIR}/sshd_config" /etc/ssh/sshd_config - systemctl restart sshd 2>/dev/null || true - print_success "Configuration SSH restaurée" - else - print_warning "Sauvegarde SSH non trouvée" - fi -} - -restore_ufw_config() { - if command -v ufw > /dev/null 2>&1; then - ufw --force reset > /dev/null 2>&1 || true - print_success "Configuration UFW réinitialisée" - fi -} - -restore_fail2ban_config() { - if [[ -f "${BACKUP_DIR}/jail.local" ]]; then - cp "${BACKUP_DIR}/jail.local" /etc/fail2ban/jail.local 2>/dev/null || true - systemctl restart fail2ban 2>/dev/null || true - print_success "Configuration Fail2ban restaurée" - fi -} - -restore_all_configs() { - restore_ssh_config - restore_ufw_config - restore_fail2ban_config -} - -list_all_steps() { - echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}║ LISTE DES ÉTAPES DISPONIBLES ║${NC}" - echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" - - local i=1 - for step_name in "${!STEP_DESCRIPTIONS[@]}"; do - local status="❌ Non exécutée" - if check_step_done "$step_name" 2>/dev/null; then - status="✅ Terminée" - fi - - printf "${BLUE}%2d.${NC} %-35s ${GREEN}%-12s${NC}\n" \ - "$i" "${STEP_DESCRIPTIONS[$step_name]}" "$status" - i=$((i + 1)) - done - - echo "" - echo -e "${YELLOW}COMMANDES DE CONTRÔLE:${NC}" - echo " --force-step=NOM Forcer une étape spécifique" - echo " --force-all Forcer toutes les étapes" - echo " --skip-step=NOM Sauter une étape spécifique" - echo " --reset-step=NOM Réinitialiser une étape" - echo " --reset-all Réinitialiser toutes les étapes" - echo " --list-steps Lister toutes les étapes" - echo " --show-status Afficher le statut des étapes" - echo "" - - if [[ -f "$STATUS_FILE" ]]; then - local completed_count=$(wc -l < "$STATUS_FILE" 2>/dev/null || echo 0) - echo -e "${GREEN}Étapes terminées: $completed_count/${#STEP_DESCRIPTIONS[@]}${NC}" - fi -} - -show_step_status() { - echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}║ STATUT DES ÉTAPES ║${NC}" - echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" - - local completed=0 - local total=${#STEP_DESCRIPTIONS[@]} - - local step_order=( - "install_security_tools" - "detect_open_ports" - "configure_process_accounting" - "configure_sysctl_security" - "configure_log_permissions" - "configure_pam_password_policy" - "configure_login_defs" - "configure_umask" - "configure_aide_sha512" - "initialize_aide_db" - "configure_clamav" - "configure_chrony" - "harden_ssh" - "configure_banners" - "configure_firewall_ports" - "configure_fail2ban" - "remove_unneeded_packages" - "restrict_file_permissions" - "disable_risky_kernel_modules" - "configure_security_limits" - "verify_packages_integrity" - "configure_automatic_updates" - "configure_aide_cron" - "harden_smtp_banner" - "harden_systemd_services" - "configure_advanced_pam" - "check_partition_layout" - "check_vmlinuz" - "run_chkrootkit" - "prepare_ssh_cleanup" - "run_lynis_audit" - ) - - for step_name in "${step_order[@]}"; do - local description="${STEP_DESCRIPTIONS[$step_name]}" - local status_color=$RED - local status_icon="❌" - local status_text="Non exécutée" - - if check_step_done "$step_name" 2>/dev/null; then - status_color=$GREEN - status_icon="✅" - status_text="Terminée" - completed=$((completed + 1)) - fi - - local extra_info="" - if [[ " ${FORCE_STEPS[@]} " =~ " ${step_name} " ]]; then - extra_info=" [FORCÉ]" - elif [[ " ${SKIP_STEPS[@]} " =~ " ${step_name} " ]]; then - extra_info=" [IGNORÉ]" - fi - - echo -e "${status_icon} ${status_color}${description}${NC}${extra_info}" - done - - echo "" - echo -e "${YELLOW}RÉSUMÉ:${NC}" - echo -e " Progression: ${completed}/${total} étapes" - - local width=50 - local percent=$((completed * 100 / total)) - local filled=$((percent * width / 100)) - local empty=$((width - filled)) - - echo -n " [" - for ((i=0; i/dev/null || echo "Inconnu")" - fi -} - -# ============================================================================== -# PARSING DES ARGUMENTS -# ============================================================================== - -parse_arguments() { - while [[ $# -gt 0 ]]; do - case $1 in - --force-all) - FORCE_ALL=true - print_warning "Mode FORCE ALL activé - Toutes les étapes seront ré-exécutées" - shift - ;; - --force-step=*) - local step="${1#*=}" - FORCE_STEPS+=("$step") - print_info "Étape forcée: $step" - shift - ;; - --skip-step=*) - local step="${1#*=}" - SKIP_STEPS+=("$step") - print_info "Étape ignorée: $step" - shift - ;; - --reset-step=*) - local step="${1#*=}" - reset_step "$step" - exit 0 - ;; - --reset-all) - reset_all_steps - exit 0 - ;; - --list-steps) - LIST_STEPS=true - shift - ;; - --show-status) - SHOW_STATUS=true - shift - ;; - --cleanup-ssh) - shift - ;; - --help|-h) - show_help - exit 0 - ;; - *) - print_error "Option inconnue: $1" - show_help - exit 1 - ;; - esac - done -} - -show_help() { - echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}║ AIDE - SYSTEM HARDENING SCRIPT v8.0 ║${NC}" - echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" - echo -e "${GREEN}USAGE:${NC}" - echo " $0 [OPTIONS]" - echo "" - echo -e "${GREEN}OPTIONS:${NC}" - echo " --force-all Forcer l'exécution de toutes les étapes" - echo " --force-step=NOM Forcer une étape spécifique" - echo " --skip-step=NOM Sauter une étape spécifique" - echo " --reset-step=NOM Réinitialiser une étape (la marquer comme non faite)" - echo " --reset-all Réinitialiser toutes les étapes" - echo " --list-steps Lister toutes les étapes disponibles" - echo " --show-status Afficher le statut des étapes" - echo " --cleanup-ssh Nettoyer le port SSH 22 (après test)" - echo " --help, -h Afficher cette aide" - echo "" - echo -e "${YELLOW}EXEMPLES:${NC}" - echo " # Exécution normale" - echo " $0" - echo "" - echo " # Forcer uniquement la configuration SSH" - echo " $0 --force-step=harden_ssh" - echo "" - echo " # Forcer SSH et UFW, sauter Fail2ban" - echo " $0 --force-step=harden_ssh --force-step=configure_firewall_ports --skip-step=configure_fail2ban" - echo "" - echo " # Réinitialiser uniquement la configuration SSH" - echo " $0 --reset-step=harden_ssh" - echo "" - echo " # Voir le statut des étapes" - echo " $0 --show-status" - echo "" - echo -e "${RED}⚠ AVERTISSEMENT:${NC}" - echo " Le forçage d'étapes peut écraser des configurations existantes." - echo " Assurez-vous d'avoir des sauvegardes avant d'utiliser --force-all." -} - # ============================================================================== # FONCTIONS DE DÉTECTION DES PORTS # ============================================================================== detect_open_ports() { local step_name="detect_open_ports" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Détection des ports ouverts" print_info "Scan des ports en écoute localement..." + # Utiliser ss pour détecter les ports en écoute ss -tlnp | grep LISTEN | awk '{print $4}' | awk -F: '{print $NF}' | sort -n | uniq > "$OPEN_PORTS_FILE" 2>/dev/null || { + # Fallback sur netstat si ss n'est pas disponible netstat -tlnp 2>/dev/null | grep LISTEN | awk '{print $4}' | awk -F: '{print $NF}' | sort -n | uniq > "$OPEN_PORTS_FILE" || { print_warning "Impossible de détecter les ports ouverts" touch "$OPEN_PORTS_FILE" @@ -616,20 +180,19 @@ get_ssh_port_to_use() { echo "22" fi else + # Pour les systèmes physiques/VMs, utiliser le nouveau port echo "22022" fi } # ============================================================================== -# FONCTIONS DE DURCISSEMENT +# FONCTIONS DE DURCISSEMENT (adaptées) # ============================================================================== +# ÉTAPE 1: Mise à jour système et installation outils install_security_tools() { local step_name="install_security_tools" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Mise à jour système et installation outils de sécurité" @@ -652,13 +215,417 @@ install_security_tools() { mark_step_done "$step_name" } -configure_process_accounting() { - local step_name="configure_process_accounting" +# ÉTAPE 2: Détection des ports ouverts (déjà définie plus haut) +configure_firewall_ports() { + local step_name="configure_firewall_ports" if check_step_done "$step_name"; then skip_step "${STEP_DESCRIPTIONS[$step_name]}" return 0 fi + print_step "Configuration des règles de pare-feu basées sur les ports détectés" + + # Vérifier si on est dans un conteneur + if detect_container; then + print_warning "Conteneur détecté - pare-feu géré par l'hôte Proxmox" + print_info "UFW ne peut pas être configuré dans un conteneur LXC" + + # Désactiver UFW s'il est actif + if systemctl is-active --quiet ufw 2>/dev/null; then + ufw --force disable 2>/dev/null || true + systemctl stop ufw 2>/dev/null || true + systemctl disable ufw 2>/dev/null || true + systemctl mask ufw 2>/dev/null || true + print_info "Service UFW désactivé (non nécessaire en conteneur)" + fi + + print_success "Configuration pare-feu ignorée (environnement conteneurisé)" + mark_step_done "$step_name" + return 0 + fi + + # Configuration pour système physique/VM + backup_file "/etc/ufw/user.rules" + backup_file "/etc/ufw/user6.rules" + + print_info "Réinitialisation des règles UFW..." + ufw --force reset > /dev/null 2>&1 || { + print_error "Impossible de réinitialiser UFW" + mark_step_done "$step_name" + return 1 + } + + print_info "Configuration des politiques par défaut..." + ufw default deny incoming + ufw default allow outgoing + + # Déterminer le port SSH à utiliser + local ssh_port=$(get_ssh_port_to_use) + + # Autoriser le port SSH + print_info "Autorisation du port SSH $ssh_port..." + if ufw allow "${ssh_port}/tcp" comment 'SSH sécurisé' > /dev/null 2>&1; then + print_info " ✓ Port SSH $ssh_port autorisé" + else + print_warning " ✗ Erreur avec le port SSH $ssh_port" + fi + + # Si on utilise un port différent de 22 et que le port 22 est ouvert, l'autoriser temporairement + if [[ "$ssh_port" != "22" ]] && is_port_open "22"; then + print_info "Autorisation temporaire du port SSH 22 (à désactiver après test)..." + if ufw allow "22/tcp" comment 'SSH temporaire (à désactiver)' > /dev/null 2>&1; then + print_info " ✓ Port SSH 22 autorisé temporairement" + else + print_warning " ✗ Erreur avec le port SSH 22" + fi + fi + + # Définition des services courants avec leurs ports (version simplifiée) + declare -A service_ports=( + # Services web essentiels + ["HTTP"]="80" + ["HTTPS"]="443" + + # Services réseau de base + ["DNS"]="53" + ["DNS-UDP"]="53/udp" + ["NTP"]="123" + ["NTP-UDP"]="123/udp" + + # Email + ["SMTP"]="25" + ["SMTP-Submission"]="587" + ["SMTPS"]="465" + ["IMAP"]="143" + ["IMAPS"]="993" + ["POP3"]="110" + ["POP3S"]="995" + + # Base de données + ["MySQL"]="3306" + ["PostgreSQL"]="5432" + ["MongoDB"]="27017" + ["Redis"]="6379" + ["Elasticsearch"]="9200" + + # Monitoring & Logging + ["Graylog-Web"]="9000" + ["Graylog-API"]="12900" + ["Prometheus"]="9090" + ["Grafana"]="3000" + ["Node-Exporter"]="9100" + + # Services spécifiques demandés + ["Ollama"]="11434" + ["Gitea"]="3000" + ["Gitea-SSH"]="2222" + ["Bitwarden"]="80 443" + ["Teleport"]="3022 3023 3024 3025 3026" + ["NetBox"]="8000" + ["Wazuh"]="1514 1515 55000" + + # Services AD/Samba + ["Active-Directory"]="53 88 135 137 138 139 389 445 464 636 3268 3269" + ["Samba"]="137 138 139 445" + ["LDAP"]="389" + ["LDAPS"]="636" + ["Kerberos"]="88" + + # DevOps + ["Docker"]="2375 2376" + ["Kubernetes"]="6443 10250" + ["Jenkins"]="8080" + ["GitLab"]="80 443 22" + + # Virtualisation + ["Proxmox"]="8006" + ["VNC"]="5900" + ["RDP"]="3389" + ) + + print_info "Analyse des ports ouverts pour services connus..." + local services_authorized=0 + local total_services=${#service_ports[@]} + local current_service=0 + + # Parcourir tous les services + for service_name in "${!service_ports[@]}"; do + current_service=$((current_service + 1)) + local ports="${service_ports[$service_name]}" + local ports_array=($ports) + + # Vérifier chaque port du service + for port_entry in "${ports_array[@]}"; do + # Extraire le numéro de port (sans /udp ou /tcp) + local port_num=$(echo "$port_entry" | grep -o '^[0-9]*') + + # Vérifier si c'est une plage de ports + if [[ "$port_num" =~ ^[0-9]+-[0-9]+$ ]]; then + local start_port=$(echo "$port_num" | cut -d'-' -f1) + local end_port=$(echo "$port_num" | cut -d'-' -f2) + + # Vérifier si au moins un port de la plage est ouvert + local range_detected=false + for ((p=start_port; p<=end_port; p++)); do + if is_port_open "$p"; then + range_detected=true + break + fi + done + + if $range_detected; then + echo -e "${YELLOW}[$current_service/$total_services] Plage de ports détectée: $port_entry ($service_name)${NC}" + read -p " Autoriser la plage $start_port:$end_port ? (o/N): " -r confirm_range + + if [[ "$confirm_range" =~ ^[OoYy]$ ]]; then + # Déterminer le protocole + if [[ "$port_entry" == *"/udp" ]]; then + if ufw allow "$start_port:$end_port/udp" comment "$service_name" > /dev/null 2>&1; then + services_authorized=$((services_authorized + 1)) + print_info " ✓ Plage $start_port:$end_port/udp autorisée" + else + print_warning " ✗ Erreur avec la plage $port_entry" + fi + else + if ufw allow "$start_port:$end_port/tcp" comment "$service_name" > /dev/null 2>&1; then + services_authorized=$((services_authorized + 1)) + print_info " ✓ Plage $start_port:$end_port/tcp autorisée" + else + print_warning " ✗ Erreur avec la plage $port_entry" + fi + fi + else + print_info " ✗ Plage $port_entry non autorisée" + fi + fi + else + # Port unique + if is_port_open "$port_num"; then + echo -e "${YELLOW}[$current_service/$total_services] Port $port_entry détecté ($service_name)${NC}" + + # Demander confirmation + read -p " Autoriser ce port ? (o/N): " -r confirm_port + + if [[ "$confirm_port" =~ ^[OoYy]$ ]]; then + # Déterminer le protocole + if [[ "$port_entry" == *"/udp" ]]; then + if ufw allow "$port_num/udp" comment "$service_name" > /dev/null 2>&1; then + services_authorized=$((services_authorized + 1)) + print_info " ✓ Port $port_num/udp autorisé" + else + print_warning " ✗ Erreur avec le port $port_num/udp" + fi + else + # Par défaut, autoriser TCP + if ufw allow "$port_num/tcp" comment "$service_name" > /dev/null 2>&1; then + services_authorized=$((services_authorized + 1)) + print_info " ✓ Port $port_num/tcp autorisé" + else + print_warning " ✗ Erreur avec le port $port_num/tcp" + fi + + # Pour les ports non spécifiés, demander pour UDP aussi + if [[ ! "$port_entry" == *"/"* ]]; then + echo -n " Autoriser aussi en UDP ? (o/N): " + read -r confirm_udp + if [[ "$confirm_udp" =~ ^[OoYy]$ ]]; then + if ufw allow "$port_num/udp" comment "$service_name (UDP)" > /dev/null 2>&1; then + services_authorized=$((services_authorized + 1)) + print_info " ✓ Port $port_num/udp autorisé" + else + print_warning " ✗ Erreur avec le port $port_num/udp" + fi + fi + fi + fi + else + print_info " ✗ Port $port_entry non autorisé" + fi + fi + fi + done + done + + # Vérifier les ports restants non couverts + print_info "Recherche de ports ouverts supplémentaires..." + local unknown_ports_added=0 + + if [[ -f "$OPEN_PORTS_FILE" ]]; then + while IFS= read -r port; do + # Nettoyer le port + port=$(echo "$port" | tr -d '[:space:]') + [[ -z "$port" ]] && continue + + # Ignorer les ports déjà traités + [[ "$port" == "22" || "$port" == "22022" || "$port" == "$ssh_port" ]] && continue + + # Vérifier si le port est déjà couvert par un service + local port_covered=false + for service_name in "${!service_ports[@]}"; do + local ports="${service_ports[$service_name]}" + for port_spec in $ports; do + local check_port=$(echo "$port_spec" | grep -o '^[0-9]*') + if [[ "$check_port" == "$port" ]]; then + port_covered=true + break 2 + fi + done + done + + if ! $port_covered; then + # Chercher une description dans /etc/services + local service_desc=$(grep -E "^[^#][^[:space:]]+[[:space:]]+$port/" /etc/services 2>/dev/null | awk '{print $1}' | head -1) + + if [[ -n "$service_desc" ]]; then + echo -e "${YELLOW} Port $port détecté ($service_desc)${NC}" + else + echo -e "${YELLOW} Port $port détecté (service inconnu)${NC}" + fi + + read -p " Autoriser ce port ? (o/N): " -r confirm_port + + if [[ "$confirm_port" =~ ^[OoYy]$ ]]; then + # Autoriser TCP + if ufw allow "${port}/tcp" comment "Port $port ${service_desc:+- $service_desc}" > /dev/null 2>&1; then + unknown_ports_added=$((unknown_ports_added + 1)) + print_info " ✓ Port $port/tcp autorisé" + else + print_warning " ✗ Erreur avec le port $port/tcp" + fi + + # Demander pour UDP + echo -n " Autoriser aussi en UDP ? (o/N): " + read -r confirm_udp + if [[ "$confirm_udp" =~ ^[OoYy]$ ]]; then + if ufw allow "${port}/udp" comment "Port $port/udp ${service_desc:+- $service_desc}" > /dev/null 2>&1; then + unknown_ports_added=$((unknown_ports_added + 1)) + print_info " ✓ Port $port/udp autorisé" + else + print_warning " ✗ Erreur avec le port $port/udp" + fi + fi + else + print_info " ✗ Port $port non autorisé" + fi + fi + done < "$OPEN_PORTS_FILE" + else + print_warning "Fichier des ports détectés non trouvé" + fi + + # Configuration ICMP (limitation des pings) + print_info "Configuration de la limitation ICMP..." + if [[ -f /etc/ufw/before.rules ]]; then + backup_file "/etc/ufw/before.rules" + + # Ajouter la limitation ICMP si elle n'existe pas déjà + if ! grep -q "Limiter pings" /etc/ufw/before.rules; then + # Chercher la ligne avant la fin du fichier + local insert_line=$(grep -n "^COMMIT" /etc/ufw/before.rules | head -1 | cut -d: -f1) + + if [[ -n "$insert_line" ]]; then + # Insérer avant COMMIT + sed -i "${insert_line}i# Limiter pings\n-A ufw-before-input -p icmp --icmp-type echo-request -m limit --limit 3/second --limit-burst 5 -j ACCEPT\n-A ufw-before-input -p icmp --icmp-type echo-request -j DROP" /etc/ufw/before.rules + print_info " ✓ Limitation ICMP configurée" + else + # Ajouter à la fin + echo -e "\n# Limiter pings" >> /etc/ufw/before.rules + echo "-A ufw-before-input -p icmp --icmp-type echo-request -m limit --limit 3/second --limit-burst 5 -j ACCEPT" >> /etc/ufw/before.rules + echo "-A ufw-before-input -p icmp --icmp-type echo-request -j DROP" >> /etc/ufw/before.rules + print_info " ✓ Limitation ICMP ajoutée" + fi + else + print_info " ⏭ Limitation ICMP déjà configurée" + fi + fi + + # Activer UFW + print_info "Activation du pare-feu UFW..." + + # Désactiver d'abord pour éviter les conflits + ufw --force disable > /dev/null 2>&1 || true + + # Activer avec confirmation automatique + if ufw --force enable > /dev/null 2>&1; then + print_success "Pare-feu UFW configuré et activé" + + # Afficher les statistiques + echo "" + echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${GREEN} RÉSUMÉ DE LA CONFIGURATION DU PAREFEU ${NC}" + echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" + echo -e "${BLUE}Services autorisés:${NC} $services_authorized" + echo -e "${BLUE}Ports personnalisés:${NC} $unknown_ports_added" + echo -e "${BLUE}Port SSH principal:${NC} $ssh_port" + if [[ "$ssh_port" != "22" ]] && is_port_open "22"; then + echo -e "${YELLOW}Port SSH temporaire:${NC} 22 (à désactiver après test)" + fi + echo "" + + # Afficher le statut UFW + print_info "Statut UFW actuel:" + echo -e "${CYAN}══════════════════════════════════════════════════════════════${NC}" + ufw status verbose | head -20 + echo -e "${CYAN}══════════════════════════════════════════════════════════════${NC}" + + else + # Fallback avec confirmation interactive + print_warning "Échec de l'activation automatique, tentative manuelle..." + if ufw enable <<< 'y' > /dev/null 2>&1; then + print_success "Pare-feu UFW activé (mode manuel)" + else + print_error "Échec critique de l'activation UFW" + print_info "Le pare-feu reste désactivé - vérifiez la configuration" + fi + fi + + # Sauvegarder la configuration + cat > "$BACKUP_DIR/firewall_config_$(date +%Y%m%d_%H%M%S).log" << EOF +=== CONFIGURATION DU PAREFEU === +Date: $(date) +Hostname: $(hostname) +Port SSH utilisé: $ssh_port + +Ports ouverts détectés: +$(cat "$OPEN_PORTS_FILE" 2>/dev/null || echo "Aucun port détecté") + +Services autorisés: $services_authorized +Ports personnalisés: $unknown_ports_added + +Configuration UFW actuelle: +$(ufw status) + +=== FIN DE CONFIGURATION === +EOF + + print_info "Configuration sauvegardée dans: $BACKUP_DIR/firewall_config_*.log" + + # Instructions importantes + if [[ "$ssh_port" == "22022" ]]; then + echo "" + echo -e "${RED}══════════════════════════════════════════════════════════════════${NC}" + echo -e "${RED} ⚠ IMPORTANT ⚠ ${NC}" + echo -e "${RED}══════════════════════════════════════════════════════════════════${NC}" + echo "" + echo -e "${YELLOW}1. Testez immédiatement le nouveau port SSH:${NC}" + echo " ssh -p 22022 $(whoami)@$(hostname -I | awk '{print $1}')" + echo "" + echo -e "${YELLOW}2. Une fois confirmé, supprimez le port 22 avec:${NC}" + echo " $0 --cleanup-ssh" + echo "" + echo -e "${RED}NE FERMEZ PAS CETTE SESSION AVANT DE VALIDER SSH SUR LE PORT 22022${NC}" + echo -e "${RED}══════════════════════════════════════════════════════════════════${NC}" + fi + + mark_step_done "$step_name" +} + +# ÉTAPE 3: Configuration Process Accounting +configure_process_accounting() { + local step_name="configure_process_accounting" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + print_step "Configuration du Process Accounting" if detect_container; then @@ -680,16 +647,15 @@ configure_process_accounting() { mark_step_done "$step_name" } +# ÉTAPE 4: Durcissement sysctl configure_sysctl_security() { local step_name="configure_sysctl_security" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Durcissement des paramètres noyau (sysctl)" cat > /etc/sysctl.d/99-security-hardening.conf << 'EOF' +# Sécurité réseau IPv4 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 @@ -701,15 +667,21 @@ net.ipv4.conf.default.log_martians = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 net.ipv4.tcp_syncookies = 1 + +# Sécurité réseau IPv6 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.all.accept_source_route = 0 net.ipv6.conf.default.accept_redirects = 0 net.ipv6.conf.default.accept_source_route = 0 + +# Sécurité noyau kernel.randomize_va_space = 2 kernel.kptr_restrict = 2 kernel.dmesg_restrict = 1 kernel.yama.ptrace_scope = 1 kernel.unprivileged_bpf_disabled = 1 + +# Sécurité système fs.suid_dumpable = 0 fs.protected_fifos = 2 fs.protected_regular = 2 @@ -724,12 +696,10 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 5: Configuration permissions logs configure_log_permissions() { local step_name="configure_log_permissions" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration des permissions des fichiers de log" @@ -743,18 +713,18 @@ configure_log_permissions() { mark_step_done "$step_name" } +# ÉTAPE 6: Politique mots de passe PAM configure_pam_password_policy() { local step_name="configure_pam_password_policy" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration de la politique de mots de passe PAM" backup_file "/etc/security/pwquality.conf" cat >> /etc/security/pwquality.conf << 'EOF' + +# Configuration renforcée minlen = 14 minclass = 3 maxrepeat = 3 @@ -768,8 +738,10 @@ EOF backup_file "/etc/pam.d/common-password" + # Ajouter remember et sha512 sed -i 's/pam_unix.so.*/& remember=5 sha512 rounds=500000/' /etc/pam.d/common-password + # Ajouter pwquality si absent grep -q "pam_pwquality.so" /etc/pam.d/common-password || \ sed -i '1i password requisite pam_pwquality.so retry=3' /etc/pam.d/common-password @@ -777,12 +749,10 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 7: Configuration login.defs configure_login_defs() { local step_name="configure_login_defs" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration des paramètres de connexion (login.defs)" @@ -802,12 +772,10 @@ configure_login_defs() { mark_step_done "$step_name" } +# ÉTAPE 8: Configuration umask global configure_umask() { local step_name="configure_umask" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration de l'umask par défaut" @@ -821,12 +789,10 @@ configure_umask() { mark_step_done "$step_name" } +# ÉTAPE 9: Configuration AIDE SHA512 configure_aide_sha512() { local step_name="configure_aide_sha512" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration AIDE pour SHA512" @@ -840,16 +806,14 @@ configure_aide_sha512() { mark_step_done "$step_name" } +# ÉTAPE 10: Initialisation AIDE initialize_aide_db() { local step_name="initialize_aide_db" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Initialisation de la base de données AIDE" - print_info "Création de la base de données de référence..." + print_info "Création de la base de données de référence (peut prendre plusieurs minutes)..." if command -v aideinit > /dev/null; then aideinit && print_success "Base de données AIDE initialisée via aideinit" || { @@ -874,18 +838,16 @@ initialize_aide_db() { mark_step_done "$step_name" } +# ÉTAPE 11: Configuration ClamAV configure_clamav() { local step_name="configure_clamav" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration de ClamAV" print_info "Mise à jour de la base de données ClamAV..." systemctl stop clamav-freshclam 2>/dev/null || true - freshclam || print_warning "Échec mise à jour ClamAV" + freshclam || print_warning "Échec mise à jour ClamAV (normal si déjà récent)" systemctl enable clamav-freshclam systemctl start clamav-freshclam @@ -896,60 +858,67 @@ configure_clamav() { mark_step_done "$step_name" } +# ÉTAPE 12: Configuration Chrony configure_chrony() { local step_name="configure_chrony" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration de la synchronisation horaire (Chrony)" + # Vérifier si on est dans un conteneur if detect_container; then print_warning "Conteneur détecté - synchronisation horaire gérée par l'hôte" + print_info "La configuration de Chrony est ignorée en environnement conteneurisé" + # Désactiver/masquer chrony s'il est présent if systemctl list-unit-files | grep -q "^chrony.service"; then systemctl stop chrony 2>/dev/null || true systemctl disable chrony 2>/dev/null || true systemctl mask chrony 2>/dev/null || true - print_info "Service Chrony désactivé" + print_info "Service Chrony désactivé (non nécessaire en conteneur)" fi mark_step_done "$step_name" return 0 fi + # Configuration pour système physique/VM backup_file "/etc/chrony/chrony.conf" + # Configurer le fuseau horaire timedatectl set-timezone Europe/Paris || { print_warning "Impossible de définir le fuseau horaire" } cat > /etc/chrony/chrony.conf << 'EOF' +# Serveurs NTP pool 2.debian.pool.ntp.org iburst server 0.fr.pool.ntp.org iburst server 1.fr.pool.ntp.org iburst + +# Fichiers de drift et log driftfile /var/lib/chrony/chrony.drift logdir /var/log/chrony + +# Restrictions makestep 1.0 3 rtcsync EOF + # Activer et démarrer le service if systemctl enable chrony 2>/dev/null && systemctl restart chrony 2>/dev/null; then print_success "Chrony configuré et démarré" else - print_warning "Erreur lors du démarrage de Chrony" + print_warning "Erreur lors du démarrage de Chrony - service peut-être non disponible" fi mark_step_done "$step_name" } +# ÉTAPE 13: Durcissement SSH (adapté pour LXC) harden_ssh() { local step_name="harden_ssh" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Durcissement du service SSH" @@ -957,27 +926,36 @@ harden_ssh() { local sshd_config="/etc/ssh/sshd_config" + # Fonction helper pour mettre à jour une valeur update_ssh_param() { local param="$1" local value="$2" local file="$3" + + # Supprimer toutes les occurrences (commentées ou non) sed -i "/^#*${param}/d" "$file" + # Ajouter la nouvelle valeur echo "${param} ${value}" >> "$file" } + # Déterminer le port SSH à utiliser local ssh_port=$(get_ssh_port_to_use) + # Configuration des ports sed -i '/^Port /d' "$sshd_config" sed -i '/^#Port /d' "$sshd_config" echo "Port $ssh_port" >> "$sshd_config" + # Si LXC et port 22022 non ouvert, garder aussi le port 22 if detect_lxc && [[ "$ssh_port" == "22" ]]; then - print_info "LXC détecté - port 22 maintenu" + print_info "LXC détecté - port 22 maintenu (port 22022 non disponible)" elif [[ "$ssh_port" == "22022" ]]; then + # Pour les systèmes non-LXC ou LXC avec port 22022 ouvert, ajouter le port 22 temporairement echo "Port 22" >> "$sshd_config" - print_info "Port 22 ajouté temporairement" + print_info "Port 22 ajouté temporairement (à désactiver après test)" fi + # Paramètres de sécurité avec la fonction helper update_ssh_param "PermitRootLogin" "yes" "$sshd_config" update_ssh_param "PasswordAuthentication" "no" "$sshd_config" update_ssh_param "PubkeyAuthentication" "yes" "$sshd_config" @@ -995,26 +973,33 @@ harden_ssh() { update_ssh_param "Compression" "no" "$sshd_config" update_ssh_param "Protocol" "2" "$sshd_config" + # Algorithmes sécurisés (s'assurer qu'ils n'existent pas déjà) sed -i '/^Ciphers /d' "$sshd_config" sed -i '/^MACs /d' "$sshd_config" sed -i '/^KexAlgorithms /d' "$sshd_config" cat >> "$sshd_config" << 'EOF' + +# Algorithmes cryptographiques sécurisés Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 EOF + # Bannière update_ssh_param "Banner" "/etc/issue.net" "$sshd_config" + # Test de la configuration avant application print_info "Test de la configuration SSH..." if sshd -t 2>&1 | tee -a "$LOG_FILE"; then print_success "Configuration SSH valide" + # Redémarrer le service print_info "Redémarrage du service SSH..." if systemctl restart sshd 2>/dev/null || systemctl restart ssh 2>/dev/null; then print_success "SSH durci avec succès" + # Afficher les ports configurés local ports=$(grep "^Port" "$sshd_config" | awk '{print $2}' | tr '\n' ' ') print_info "Ports SSH actifs: $ports" @@ -1047,12 +1032,10 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 14: Configuration bannières configure_banners() { local step_name="configure_banners" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration des bannières légales" @@ -1072,387 +1055,21 @@ configure_banners() { mark_step_done "$step_name" } -configure_firewall_ports() { - local step_name="configure_firewall_ports" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi - - print_step "Configuration des règles de pare-feu basées sur les ports détectés" - - if detect_container; then - print_warning "Conteneur détecté - pare-feu géré par l'hôte Proxmox" - print_info "UFW ne peut pas être configuré dans un conteneur LXC" - - if systemctl is-active --quiet ufw 2>/dev/null; then - ufw --force disable 2>/dev/null || true - systemctl stop ufw 2>/dev/null || true - systemctl disable ufw 2>/dev/null || true - systemctl mask ufw 2>/dev/null || true - print_info "Service UFW désactivé" - fi - - print_success "Configuration pare-feu ignorée" - mark_step_done "$step_name" - return 0 - fi - - backup_file "/etc/ufw/user.rules" - backup_file "/etc/ufw/user6.rules" - - print_info "Réinitialisation des règles UFW..." - ufw --force reset > /dev/null 2>&1 || { - print_error "Impossible de réinitialiser UFW" - mark_step_done "$step_name" - return 1 - } - - print_info "Configuration des politiques par défaut..." - ufw default deny incoming - ufw default allow outgoing - - local ssh_port=$(get_ssh_port_to_use) - - print_info "Autorisation du port SSH $ssh_port..." - ufw allow "${ssh_port}/tcp" comment 'SSH sécurisé' || print_warning "Erreur ajout règle SSH:${ssh_port}" - - if [[ "$ssh_port" != "22" ]] && is_port_open "22"; then - print_info "Autorisation temporaire du port SSH 22..." - ufw allow 22/tcp comment 'SSH temporaire (à désactiver)' || print_warning "Erreur ajout règle SSH:22" - fi - - declare -A service_ports=( - ["HTTP"]="80" - ["HTTPS"]="443" - ["DNS"]="53" - ["DNS-TCP"]="53/tcp" - ["DNS-UDP"]="53/udp" - ["NTP"]="123" - ["NTP-UDP"]="123/udp" - ["SMTP"]="25" - ["SMTP-Submission"]="587" - ["SMTPS"]="465" - ["IMAP"]="143" - ["IMAPS"]="993" - ["POP3"]="110" - ["POP3S"]="995" - ["FTP"]="21" - ["FTP-Data"]="20" - ["FTP-SSL"]="990" - ["SFTP"]="22" - ["MySQL"]="3306" - ["PostgreSQL"]="5432" - ["MongoDB"]="27017" - ["Redis"]="6379" - ["Redis-Sentinel"]="26379" - ["Elasticsearch"]="9200" - ["Elasticsearch-Cluster"]="9300" - ["Graylog-Web"]="9000" - ["Graylog-API"]="12900" - ["Graylog-Syslog"]="514" - ["Graylog-Syslog-UDP"]="514/udp" - ["Wazuh-Manager"]="1514" - ["Wazuh-Manager-UDP"]="1514/udp" - ["Wazuh-API"]="55000" - ["Prometheus"]="9090" - ["Grafana"]="3000" - ["Node-Exporter"]="9100" - ["Zabbix-Server"]="10051" - ["Zabbix-Agent"]="10050" - ["Docker-Registry"]="5000" - ["Docker-API"]="2375" - ["Docker-API-TLS"]="2376" - ["Kubernetes-API"]="6443" - ["Kubelet-API"]="10250" - ["Kube-Proxy"]="10256" - ["LDAP"]="389" - ["LDAPS"]="636" - ["LDAP-Global-Catalog"]="3268" - ["LDAPS-Global-Catalog"]="3269" - ["Kerberos"]="88" - ["Kerberos-UDP"]="88/udp" - ["SMB"]="445" - ["SMB-UDP"]="445/udp" - ["NetBIOS"]="139" - ["RDP"]="3389" - ["VNC"]="5900" - ["VNC-Web"]="5800" - ["Matrix-Synapse"]="8008" - ["Matrix-Synapse-TLS"]="8448" - ["Rocket.Chat"]="3000" - ["Mattermost"]="8065" - ["Zulip"]="9991" - ["Ansible"]="22" - ["Salt-Master"]="4505 4506" - ["Puppet"]="8140" - ["Chef-Server"]="9463" - ["NFS"]="2049" - ["NFS-UDP"]="2049/udp" - ["NFS-Mount"]="20048" - ["Samba"]="137 138 139 445" - ["Samba-UDP"]="137/udp 138/udp" - ["GlusterFS"]="24007 24008 49152-49251" - ["Ceph-Mon"]="6789" - ["Ceph-OSD"]="6800-7300" - ["Bacula-Director"]="9101" - ["Bacula-Storage"]="9103" - ["Bacula-Client"]="9102" - ["Proxmox-Web"]="8006" - ["Proxmox-VNC"]="5900-5999" - ["Proxmox-SPN"]="3128" - ["VMware-ESXi"]="902" - ["VirtualBox-RDP"]="3389" - ["Gitea"]="3000" - ["Gitea-SSH"]="2222" - ["Bitwarden"]="80 443" - ["Bitwarden-Admin"]="8000" - ["Ollama-API"]="11434" - ["Teleport-Auth"]="3025" - ["Teleport-Proxy"]="3023 3024" - ["Teleport-SSH"]="3022" - ["Teleport-Kube"]="3026" - ["NetBox"]="8000" - ["NetBox-SSL"]="8443" - ["Nextcloud"]="80 443" - ["Jitsi-Meet"]="80 443 10000/udp" - ["Jitsi-Videobridge"]="4443" - ["Jellyfin"]="8096" - ["Jellyfin-SSL"]="8920" - ["Plex"]="32400" - ["Emby"]="8096" - ["Emby-SSL"]="8920" - ["GitLab"]="80 443 22" - ["Jenkins"]="8080" - ["Jenkins-Slave"]="50000" - ["SonarQube"]="9000" - ["Nexus"]="8081" - ["Harbor"]="80 443" - ["Harbor-API"]="8280" - ["TheHive"]="9000" - ["Cortex"]="9001" - ["MISP"]="80 443" - ["OpenCTI"]="8080" - ["Velociraptor"]="8000 8889" - ["Suricata"]="" - ["Asterisk"]="5060 5061" - ["Asterisk-UDP"]="5060/udp" - ["FreePBX"]="80 443" - ["FreeSWITCH"]="5060 5080 8021" - ["RabbitMQ"]="5672 5671 15672" - ["RabbitMQ-Management"]="15672" - ["Mosquitto"]="1883 8883" - ["Mosquitto-Websocket"]="8083 8084" - ["Memcached"]="11211" - ["Memcached-UDP"]="11211/udp" - ["Beanstalkd"]="11300" - ["Kong"]="8000 8001 8443 8444" - ["Tyk"]="8080" - ["Ethereum"]="30303" - ["Ethereum-UDP"]="30303/udp" - ["Bitcoin"]="8333" - ["Bitcoin-Testnet"]="18333" - ["Minecraft"]="25565" - ["Minecraft-Bedrock"]="19132/udp" - ["Steam"]="27015 27016 27017 27018 27019 27020" - ["Steam-UDP"]="27015/udp 27016/udp 27017/udp 27018/udp 27019/udp 27020/udp" - ["Home Assistant"]="8123" - ["Home Assistant-SSL"]="443" - ["MQTT-Home"]="1883" - ["Zigbee2MQTT"]="8080" - ["Active Directory"]="53 88 135 137 138 139 389 445 464 636 3268 3269" - ["AD-UDP"]="53/udp 88/udp 123/udp 137/udp 138/udp" - ["Exchange"]="25 80 110 143 443 465 587 993 995" - ["SharePoint"]="80 443" - ["SQL Server"]="1433" - ["RPC"]="135" - ["NetBIOS-Name"]="137/udp" - ["NetBIOS-Datagram"]="138/udp" - ["NetBIOS-Session"]="139" - ["Apple-File-Service"]="548" - ["Apple-Time-Machine"]="548" - ["Bonjour"]="5353/udp" - ["Google-Cloud-Print"]="5222" - ["Google-Cast"]="8009 8443" - ) - - print_info "Analyse des ports ouverts pour services connus..." - local services_authorized=0 - local services_skipped=0 - - for service_name in "${!service_ports[@]}"; do - local ports="${service_ports[$service_name]}" - - for port_spec in $ports; do - local port_num=$(echo "$port_spec" | sed 's|/.*||') - - if [[ "$port_num" =~ ^[0-9]+-[0-9]+$ ]]; then - local start_port=$(echo "$port_num" | cut -d'-' -f1) - local end_port=$(echo "$port_num" | cut -d'-' -f2) - - local port_in_range_open=false - for ((p=start_port; p<=end_port; p++)); do - if is_port_open "$p"; then - port_in_range_open=true - break - fi - done - - if $port_in_range_open; then - echo -e "${YELLOW} Plage de ports détectée: $port_spec ($service_name)${NC}" - read -p " Autoriser la plage $port_spec ? (o/N): " -r confirm_range - if [[ "$confirm_range" =~ ^[Oo]$ ]]; then - if [[ "$port_spec" == *"/udp" ]]; then - ufw allow "$start_port:$end_port/udp" comment "$service_name" && { - services_authorized=$((services_authorized + 1)) - print_info " ✓ Plage $start_port:$end_port/udp autorisée" - } || print_warning " ✗ Erreur avec la plage $port_spec" - else - ufw allow "$start_port:$end_port/tcp" comment "$service_name" && { - services_authorized=$((services_authorized + 1)) - print_info " ✓ Plage $start_port:$end_port/tcp autorisée" - } || print_warning " ✗ Erreur avec la plage $port_spec" - fi - else - print_info " ✗ Plage $port_spec non autorisée" - services_skipped=$((services_skipped + 1)) - fi - fi - else - if is_port_open "$port_num"; then - print_info " Autorisation du port $port_spec ($service_name)..." - - if [[ "$port_spec" == *"/udp" ]]; then - ufw allow "$port_num/udp" comment "$service_name" && { - services_authorized=$((services_authorized + 1)) - print_info " ✓ Port $port_num/udp autorisé" - } || print_warning " ✗ Erreur avec le port $port_num/udp" - else - ufw allow "$port_num/tcp" comment "$service_name" && { - services_authorized=$((services_authorized + 1)) - print_info " ✓ Port $port_num/tcp autorisé" - } || print_warning " ✗ Erreur avec le port $port_num/tcp" - fi - fi - fi - done - done - - print_info "Recherche de ports ouverts non reconnus..." - local unknown_ports_added=0 - - while read -r port; do - [[ "$port" == "22" || "$port" == "22022" || "$port" == "$ssh_port" ]] && continue - - local port_covered=false - for service_name in "${!service_ports[@]}"; do - local ports="${service_ports[$service_name]}" - for port_spec in $ports; do - local port_num=$(echo "$port_spec" | sed 's|/.*||') - if [[ "$port_num" == "$port" ]]; then - port_covered=true - break 2 - fi - done - done - - if ! $port_covered; then - local service_info=$(grep -E "^[^#].*[[:space:]]$port/" /etc/services 2>/dev/null | head -1) - local service_desc="" - - if [[ -n "$service_info" ]]; then - service_desc=$(echo "$service_info" | awk '{print $1}') - fi - - if [[ -n "$service_desc" ]]; then - echo -e "${YELLOW} Port $port détecté ($service_desc)${NC}" - else - echo -e "${YELLOW} Port non standard détecté: $port${NC}" - fi - - read -p " Autoriser ce port dans le pare-feu ? (o/N): " -r confirm_port - - if [[ "$confirm_port" =~ ^[Oo]$ ]]; then - ufw allow "${port}/tcp" comment "Port $port ${service_desc:+- $service_desc}" && { - unknown_ports_added=$((unknown_ports_added + 1)) - print_info " ✓ Port $port/tcp autorisé" - } || print_warning " ✗ Erreur avec le port $port/tcp" - - echo -n " Autoriser aussi en UDP ? (o/N): " - read -r confirm_udp - if [[ "$confirm_udp" =~ ^[Oo]$ ]]; then - ufw allow "${port}/udp" comment "Port $port/udp ${service_desc:+- $service_desc}" && { - unknown_ports_added=$((unknown_ports_added + 1)) - print_info " ✓ Port $port/udp autorisé" - } || print_warning " ✗ Erreur avec le port $port/udp" - fi - else - print_info " ✗ Port $port non autorisé" - fi - fi - done < "$OPEN_PORTS_FILE" - - print_info "Configuration limitation ICMP..." - if [[ -f /etc/ufw/before.rules ]]; then - backup_file "/etc/ufw/before.rules" - - if ! grep -q "Limiter pings" /etc/ufw/before.rules; then - cat >> /etc/ufw/before.rules << 'EOF' --A ufw-before-input -p icmp --icmp-type echo-request -m limit --limit 3/second --limit-burst 5 -j ACCEPT --A ufw-before-input -p icmp --icmp-type echo-request -j DROP -EOF - fi - fi - - print_info "Activation du pare-feu..." - if echo "y" | ufw --force enable > /dev/null 2>&1; then - print_success "Pare-feu UFW configuré et activé" - print_info "Services autorisés:" - print_info " • Services reconnus: $services_authorized" - print_info " • Services ignorés: $services_skipped" - print_info " • Ports personnalisés: $unknown_ports_added" - - echo "" - print_info "Statut UFW:" - ufw status numbered | head -30 - else - if ufw enable <<< 'y' > /dev/null 2>&1; then - print_success "Pare-feu UFW configuré et activé (fallback)" - else - print_warning "Échec activation UFW - continuer sans..." - fi - fi - - cat > "$BACKUP_DIR/detected_services.log" << EOF -=== SERVICES DÉTECTÉS ET CONFIGURÉS === -Date: $(date) -Hostname: $(hostname) -Port SSH utilisé: $ssh_port - -Ports ouverts détectés: $(tr '\n' ' ' < "$OPEN_PORTS_FILE") - -Services configurés dans UFW: -$(ufw status | grep -A1000 '^To' | grep -v '^To' | grep -v '^\s*$') - -=== FIN DU RAPPORT === -EOF - - mark_step_done "$step_name" -} +# ÉTAPE 15: Configuration pare-feu basée sur ports détectés (déjà définie) +# ÉTAPE 16: Configuration Fail2ban configure_fail2ban() { local step_name="configure_fail2ban" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration de Fail2ban" backup_file "/etc/fail2ban/jail.conf" + # Déterminer le port SSH local ssh_port=$(get_ssh_port_to_use) + # Configuration adaptée selon l'environnement if detect_container; then print_warning "Conteneur détecté - configuration Fail2ban limitée" @@ -1463,6 +1080,8 @@ findtime = 10m maxretry = 3 ignoreip = 127.0.0.1/8 ::1 backend = systemd + +# Mode conteneur - pas d'action iptables banaction = %(banaction_allports)s banaction_allports = iptables-multiport @@ -1473,10 +1092,12 @@ filter = sshd logpath = /var/log/auth.log maxretry = 5 bantime = 1h +# Action désactivée en conteneur (pas d'accès iptables) action = %(action_)s EOF - print_info "Fail2ban configuré en mode conteneur" + print_info "Fail2ban configuré en mode conteneur (logging seul, sans bannissement iptables)" else + # Configuration complète pour système physique/VM cat > /etc/fail2ban/jail.local << EOF [DEFAULT] bantime = 1h @@ -1499,14 +1120,16 @@ port = http,https logpath = /var/log/apache*/*error.log maxretry = 3 EOF - print_info "Fail2ban configuré en mode complet" + print_info "Fail2ban configuré en mode complet avec bannissement iptables" fi + # Activer et démarrer le service systemctl enable fail2ban 2>&1 | tee -a "$LOG_FILE" || true if systemctl restart fail2ban 2>&1 | tee -a "$LOG_FILE"; then print_success "Fail2ban configuré et démarré" + # Vérifier le statut sleep 2 if systemctl is-active --quiet fail2ban; then print_info "Statut Fail2ban: $(systemctl is-active fail2ban)" @@ -1514,18 +1137,16 @@ EOF print_warning "Fail2ban démarré mais statut incertain" fi else - print_warning "Problème au démarrage de Fail2ban" + print_warning "Problème au démarrage de Fail2ban - vérifiez les logs: journalctl -xeu fail2ban" fi mark_step_done "$step_name" } +# ÉTAPE 17: Suppression paquets inutiles remove_unneeded_packages() { local step_name="remove_unneeded_packages" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Suppression des paquets inutiles" @@ -1544,12 +1165,10 @@ remove_unneeded_packages() { mark_step_done "$step_name" } +# ÉTAPE 18: Restriction permissions restrict_file_permissions() { local step_name="restrict_file_permissions" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Restriction des permissions des fichiers critiques" @@ -1567,16 +1186,15 @@ restrict_file_permissions() { mark_step_done "$step_name" } +# ÉTAPE 19: Désactivation modules noyau disable_risky_kernel_modules() { local step_name="disable_risky_kernel_modules" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Désactivation des modules noyau risqués" cat > /etc/modprobe.d/hardening-blacklist.conf << 'EOF' +# Protocoles réseau non utilisés blacklist dccp install dccp /bin/true blacklist sctp @@ -1585,6 +1203,8 @@ blacklist rds install rds /bin/true blacklist tipc install tipc /bin/true + +# Systèmes de fichiers non utilisés blacklist cramfs install cramfs /bin/true blacklist freevxfs @@ -1599,8 +1219,12 @@ blacklist squashfs install squashfs /bin/true blacklist udf install udf /bin/true + +# FireWire (DMA attack) blacklist firewire-core install firewire-core /bin/true + +# Thunderbolt (DMA attack) blacklist thunderbolt install thunderbolt /bin/true EOF @@ -1613,21 +1237,25 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 20: Configuration limites sécurité configure_security_limits() { local step_name="configure_security_limits" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration des limites de sécurité" backup_file "/etc/security/limits.conf" cat >> /etc/security/limits.conf << 'EOF' + +# Désactiver core dumps * hard core 0 + +# Limiter les processus * soft nproc 512 * hard nproc 1024 + +# Limiter les fichiers ouverts * soft nofile 65536 * hard nofile 65536 EOF @@ -1636,28 +1264,24 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 21: Vérification intégrité paquets verify_packages_integrity() { local step_name="verify_packages_integrity" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Vérification de l'intégrité des paquets" - print_info "Vérification avec debsums..." + print_info "Vérification avec debsums (peut prendre du temps)..." debsums -s 2>&1 | tee -a "$LOG_FILE" || print_warning "Certains paquets ont des erreurs" print_success "Vérification d'intégrité terminée" mark_step_done "$step_name" } +# ÉTAPE 22: Configuration mises à jour auto configure_automatic_updates() { local step_name="configure_automatic_updates" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration des mises à jour automatiques" @@ -1666,6 +1290,7 @@ Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}-security"; "${distro_id}:${distro_codename}-updates"; }; + Unattended-Upgrade::AutoFixInterruptedDpkg "true"; Unattended-Upgrade::MinimalSteps "true"; Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; @@ -1687,12 +1312,10 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 23: Configuration tâche AIDE cron configure_aide_cron() { local step_name="configure_aide_cron" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration des vérifications AIDE planifiées" @@ -1724,12 +1347,10 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 24: Durcissement bannière SMTP harden_smtp_banner() { local step_name="harden_smtp_banner" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Durcissement bannière SMTP" @@ -1752,12 +1373,10 @@ harden_smtp_banner() { mark_step_done "$step_name" } +# ÉTAPE 25: Durcissement services systemd harden_systemd_services() { local step_name="harden_systemd_services" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Durcissement services systemd" @@ -1767,9 +1386,13 @@ harden_systemd_services() { return 0 } + # Vérifier si on est dans un conteneur if detect_container; then print_warning "Conteneur détecté - durcissement systemd limité" + print_info "Les namespaces systemd ne sont pas supportés dans les conteneurs LXC" + print_info "Le durcissement systemd est ignoré pour éviter les erreurs de démarrage" + # Nettoyer les éventuelles configurations précédentes qui pourraient causer des problèmes local services=(ssh sshd fail2ban chrony) for service in "${services[@]}"; do local unit="${service}.service" @@ -1782,17 +1405,19 @@ harden_systemd_services() { done systemctl daemon-reload - print_success "Configuration systemd nettoyée" + print_success "Configuration systemd nettoyée pour compatibilité conteneur" mark_step_done "$step_name" return 0 fi + # Configuration pour système physique/VM local services=(ssh sshd fail2ban chrony) local hardened=0 for service in "${services[@]}"; do local unit="${service}.service" + # Vérifier si le service existe et est actif ou enabled systemctl list-unit-files | grep -q "^${unit}" || continue if ! systemctl is-enabled "$unit" > /dev/null 2>&1 && \ @@ -1803,7 +1428,9 @@ harden_systemd_services() { mkdir -p "/etc/systemd/system/${unit}.d" + # Configuration de sécurité adaptée selon le service if [[ "$service" == "ssh" || "$service" == "sshd" ]]; then + # Configuration plus permissive pour SSH cat > "/etc/systemd/system/${unit}.d/security.conf" << EOF [Service] NoNewPrivileges=yes @@ -1816,6 +1443,7 @@ ProtectControlGroups=yes RestrictRealtime=yes EOF else + # Configuration standard pour les autres services cat > "/etc/systemd/system/${unit}.d/security.conf" << EOF [Service] NoNewPrivileges=yes @@ -1835,8 +1463,10 @@ EOF print_info "Service $unit durci" done + # Recharger la configuration systemd systemctl daemon-reload + # Vérifier que les services critiques démarrent toujours print_info "Vérification des services critiques..." for service in ssh sshd; do local unit="${service}.service" @@ -1856,17 +1486,16 @@ EOF mark_step_done "$step_name" } +# ÉTAPE 26: Configuration PAM avancée configure_advanced_pam() { local step_name="configure_advanced_pam" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Configuration PAM avancée" backup_file "/etc/pam.d/common-password" + # S'assurer sha512 et rounds grep -q "pam_unix.so" /etc/pam.d/common-password && { grep -q "sha512" /etc/pam.d/common-password || \ sed -i 's/pam_unix.so.*/& sha512/' /etc/pam.d/common-password @@ -1875,6 +1504,7 @@ configure_advanced_pam() { sed -i 's/pam_unix.so.*/& rounds=500000/' /etc/pam.d/common-password } + # Appliquer expiration mots de passe print_info "Application expiration mots de passe aux utilisateurs..." while IFS=: read -r user _ uid _ _ _ shell; do [[ "$uid" -ge 1000 || "$user" == "root" ]] && \ @@ -1891,12 +1521,10 @@ configure_advanced_pam() { mark_step_done "$step_name" } +# ÉTAPE 27: Vérification partitions check_partition_layout() { local step_name="check_partition_layout" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Vérification disposition partitions" @@ -1923,12 +1551,10 @@ check_partition_layout() { mark_step_done "$step_name" } +# ÉTAPE 28: Vérification fichiers noyau check_vmlinuz() { local step_name="check_vmlinuz" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Vérification fichiers noyau" @@ -1955,32 +1581,29 @@ check_vmlinuz() { mark_step_done "$step_name" } +# ÉTAPE 29: Exécution chkrootkit run_chkrootkit() { local step_name="run_chkrootkit" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Exécution de chkrootkit" print_info "Scan rootkit en cours..." chkrootkit > "$BACKUP_DIR/chkrootkit_report.log" 2>&1 || \ - print_warning "Chkrootkit a détecté des avertissements" + print_warning "Chkrootkit a détecté des avertissements (voir $BACKUP_DIR/chkrootkit_report.log)" print_success "Scan chkrootkit terminé" mark_step_done "$step_name" } +# ÉTAPE 30: Nettoyage port SSH 22 temporaire prepare_ssh_cleanup() { local step_name="prepare_ssh_cleanup" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Préparation nettoyage port SSH 22" + # Vérifier si nous avons besoin de nettoyer le port 22 local ssh_port=$(get_ssh_port_to_use) if [[ "$ssh_port" == "22022" ]]; then @@ -1995,32 +1618,36 @@ prepare_ssh_cleanup() { mark_step_done "$step_name" } +# ÉTAPE 31: Audit Lynis final run_lynis_audit() { local step_name="run_lynis_audit" - if check_step_done "$step_name"; then - skip_step "${STEP_DESCRIPTIONS[$step_name]}" - return 0 - fi + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } print_step "Exécution de l'audit Lynis" - print_info "Audit système complet en cours..." + print_info "Audit système complet en cours (peut prendre plusieurs minutes)..." + # Exécuter Lynis et sauvegarder le rapport lynis audit system --quick --no-colors > "$SECURITY_REPORT" 2>&1 + # Extraire le score de durcissement local score=$(grep -i "Hardening index" "$SECURITY_REPORT" | grep -oP '\d+' | head -1) - local max_score=100 + local max_score=100 # Score maximum standard Lynis + # Si on ne trouve pas le score dans le rapport, utiliser une valeur par défaut [[ -z "$score" ]] && score=0 + # Sauvegarder le score pour le résumé echo "$score" > "/tmp/lynis_score.txt" echo "$max_score" > "/tmp/lynis_max_score.txt" + # Calculer le pourcentage pour la barre de progression local percentage=$((score * 100 / max_score)) - local bar_length=50 + local bar_length=50 # Longueur de la barre en caractères local filled_length=$((percentage * bar_length / 100)) local empty_length=$((bar_length - filled_length)) + # Créer la barre de progression local bar="[" for ((i=0; i/dev/null; then ufw delete allow 22/tcp 2>/dev/null || true fi @@ -2170,7 +1804,7 @@ print_header() { echo -e "${CYAN}" echo "╔══════════════════════════════════════════════════════════════════╗" - echo "║ SCRIPT DE DURCISSEMENT SYSTÈME OPTIMISÉ v8.0 ║" + echo "║ SCRIPT DE DURCISSEMENT SYSTÈME OPTIMISÉ v7.0 ║" echo "║ Sécurité Debian/Ubuntu ║" echo "║ avec détection automatique des ports ║" echo "╚══════════════════════════════════════════════════════════════════╝" @@ -2203,6 +1837,7 @@ print_summary() { echo "╚══════════════════════════════════════════════════════════════════╝" echo -e "${NC}" + # Récupérer le score Lynis local lynis_score="N/A" local lynis_max_score=100 @@ -2214,9 +1849,11 @@ print_summary() { [[ -z "$lynis_score" ]] && lynis_score="N/A" fi + # Afficher le score avec barre de progression dans le résumé if [[ "$lynis_score" != "N/A" ]]; then + # Calcul de la barre de progression local percentage=$((lynis_score * 100 / lynis_max_score)) - local bar_length=25 + local bar_length=25 # Barre plus courte pour le résumé local filled_length=$((percentage * bar_length / 100)) local empty_length=$((bar_length - filled_length)) @@ -2229,6 +1866,7 @@ print_summary() { done bar+="]" + # Déterminer la couleur du score local score_color=$RED [[ $lynis_score -ge 80 ]] && score_color=$GREEN [[ $lynis_score -ge 60 && $lynis_score -lt 80 ]] && score_color=$YELLOW @@ -2244,6 +1882,7 @@ print_summary() { echo -e "\n${MAGENTA}════════════════════ RÉSUMÉ FINAL ════════════════════${NC}\n" + # Déterminer la couleur du score pour le résumé local score_color=$RED if [[ "$lynis_score" != "N/A" ]]; then [[ $lynis_score -ge 80 ]] && score_color=$GREEN @@ -2268,6 +1907,7 @@ print_summary() { echo "" fi + # Déterminer le port SSH utilisé local ssh_port=$(get_ssh_port_to_use) echo -e "${RED}🔐 ACTIONS CRITIQUES IMMÉDIATES:${NC}" @@ -2298,6 +1938,7 @@ print_summary() { echo " • Chrony: $(systemctl is-active chrony 2>/dev/null || echo "inactif (conteneur)")" echo "" + # Afficher les ports détectés et configurés if [[ -f "$OPEN_PORTS_FILE" ]]; then echo -e "${YELLOW}🌐 PORTS DÉTECTÉS ET CONFIGURÉS:${NC}" echo " • Ports ouverts détectés: $(tr '\n' ' ' < "$OPEN_PORTS_FILE" 2>/dev/null || echo "Aucun")" @@ -2315,6 +1956,7 @@ print_summary() { echo " • Ports détectés: $OPEN_PORTS_FILE" echo "" + # Statistiques Lynis détaillées if [[ -f "$SECURITY_REPORT" ]]; then local warnings=$(grep -c "Warning" "$SECURITY_REPORT" 2>/dev/null || echo "0") local suggestions=$(grep -c "Suggestion" "$SECURITY_REPORT" 2>/dev/null || echo "0") @@ -2348,6 +1990,7 @@ print_summary() { echo " 7. Rapport complet: cat $SECURITY_REPORT | less" echo "" + # Interpréter le score if [[ "$lynis_score" != "N/A" ]]; then echo -e "${CYAN}💡 INTERPRÉTATION DU SCORE:${NC}" if [[ $lynis_score -ge 80 ]]; then @@ -2372,54 +2015,28 @@ print_summary() { echo -e "${RED}══════════════════════════════════════════════════════════════════${NC}" fi + # Nettoyage rm -f /tmp/lynis_score.txt /tmp/lynis_max_score.txt 2>/dev/null || true } main() { - parse_arguments "$@" - - if $LIST_STEPS; then - list_all_steps - exit 0 - fi - - if $SHOW_STATUS; then - show_step_status - exit 0 - fi - - if [[ $# -eq 1 && "$1" == "--cleanup-ssh" ]]; then + # Mode nettoyage SSH + [[ $# -eq 1 && "$1" == "--cleanup-ssh" ]] && { cleanup_ssh_port return 0 - fi + } + # Initialisation check_requirements - - if [[ ${#FORCE_STEPS[@]} -gt 0 ]]; then - echo -e "${YELLOW}Étapes forcées:${NC} ${FORCE_STEPS[*]}" - fi - - if [[ ${#SKIP_STEPS[@]} -gt 0 ]]; then - echo -e "${YELLOW}Étapes ignorées:${NC} ${SKIP_STEPS[*]}" - fi - - if $FORCE_ALL; then - echo -e "${RED}MODE FORCE ALL ACTIVÉ - Toutes les étapes seront ré-exécutées${NC}" - echo "" - read -p "Appuyez sur Entrée pour continuer ou Ctrl+C pour annuler..." - fi - print_header log_message "==================================================" "START" - log_message "Démarrage durcissement système v8.0" "START" + log_message "Démarrage durcissement système v7.0" "START" log_message "Système: $(hostname)" "START" log_message "Type: $(detect_container && echo "Conteneur" || echo "Physique/VM")" "START" - log_message "Mode: $($FORCE_ALL && echo "FORCE ALL" || echo "Normal")" "START" - log_message "Étapes forcées: ${FORCE_STEPS[*]}" "START" - log_message "Étapes ignorées: ${SKIP_STEPS[*]}" "START" log_message "==================================================" "START" + # EXÉCUTION DES ÉTAPES install_security_tools detect_open_ports configure_process_accounting @@ -2452,19 +2069,17 @@ main() { prepare_ssh_cleanup run_lynis_audit + # Résumé print_summary log_message "==================================================" "END" log_message "Durcissement terminé - Durée: $((SECONDS / 60)) min" "END" - log_message "Mode: $($FORCE_ALL && echo "FORCE ALL" || echo "Normal")" "END" log_message "Ports détectés: $(tr '\n' ' ' < "$OPEN_PORTS_FILE" 2>/dev/null || echo "Aucun")" "END" log_message "==================================================" "END" } -# ============================================================================== -# EXÉCUTION PRINCIPALE -# ============================================================================== - +# Gestion signaux trap 'print_error "Script interrompu"; exit 130' INT TERM +# Point d'entrée [[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@" \ No newline at end of file