From 25f37d755f8057748b411295cc86e27653cff62f Mon Sep 17 00:00:00 2001 From: Johnny Date: Tue, 30 Dec 2025 14:31:52 +0000 Subject: [PATCH] Actualiser system_hardening_optimized.sh --- system_hardening_optimized.sh | 3121 +++++++++++++++------------------ 1 file changed, 1439 insertions(+), 1682 deletions(-) diff --git a/system_hardening_optimized.sh b/system_hardening_optimized.sh index c88ea7b..947cdac 100644 --- a/system_hardening_optimized.sh +++ b/system_hardening_optimized.sh @@ -1,1857 +1,1614 @@ #!/bin/bash -# Script de durcissement système Linux -# Version: 3.0 - Idempotent et Robuste -# Auteur: Optimisé pour sécurité renforcée et réutilisabilité +################################################################################ +# Script: system_hardening_optimized.sh +# Version: 6.0 +# Date: $(date +%Y-%m-%d) +# Author: Security Team +# Description: Système de durcissement sécurité pour Debian/Ubuntu LTS +# License: GPLv3 +################################################################################ set -euo pipefail -# ============================================================================ -# CONFIGURATION GLOBALE -# ============================================================================ +# ============================================================================== +# CONFIGURATION +# ============================================================================== -readonly SCRIPT_VERSION="3.0" -readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -readonly STATE_DIR="/var/lib/hardening-script" -readonly BACKUP_BASE_DIR="/root/backup_hardening" -readonly LOG_FILE="/var/log/hardening-script.log" -readonly SSH_PORT="${SSH_PORT:-2222}" -readonly LOCK_FILE="/var/run/hardening-script.lock" +readonly LOG_FILE="/var/log/system_hardening.log" +readonly STATUS_FILE="/var/log/hardening_status.log" +readonly BACKUP_DIR="/root/backup_hardening_$(date +%Y%m%d_%H%M%S)" +readonly SECURITY_REPORT="/var/log/security_report_$(date +%Y%m%d).log" +readonly NEW_SSH_PORT=22022 + +TOTAL_STEPS=30 +CURRENT_STEP=1 + +# ============================================================================== +# COULEURS +# ============================================================================== -# Couleurs readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' +readonly CYAN='\033[0;36m' readonly BLUE='\033[0;34m' readonly MAGENTA='\033[0;35m' -readonly CYAN='\033[0;36m' readonly NC='\033[0m' -# ============================================================================ +# ============================================================================== # FONCTIONS UTILITAIRES -# ============================================================================ +# ============================================================================== -# Logging amélioré avec fichier -log() { - local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1" - echo -e "${GREEN}${msg}${NC}" - echo "$msg" >> "$LOG_FILE" +log_message() { + local message="$1" + local level="${2:-INFO}" + echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] [$level] $message" | tee -a "$LOG_FILE" } -warn() { - local msg="[ATTENTION] $1" - echo -e "${YELLOW}${msg}${NC}" - echo "$msg" >> "$LOG_FILE" +print_step() { + local step_title="$1" + echo -e "\n${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${YELLOW} ÉTAPE ${CURRENT_STEP}/${TOTAL_STEPS}: $step_title${NC}" + echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}" + log_message "Début étape $CURRENT_STEP: $step_title" "STEP" + CURRENT_STEP=$((CURRENT_STEP + 1)) } -error() { - local msg="[ERREUR] $1" - echo -e "${RED}${msg}${NC}" >&2 - echo "$msg" >> "$LOG_FILE" +print_success() { + echo -e "${GREEN}✓${NC} $1" + log_message "$1" "SUCCESS" } -info() { - local msg="[INFO] $1" - echo -e "${CYAN}${msg}${NC}" - echo "$msg" >> "$LOG_FILE" +print_warning() { + echo -e "${YELLOW}⚠${NC} $1" + log_message "$1" "WARNING" } -success() { - local msg="[OK] $1" - echo -e "${GREEN}${msg}${NC}" - echo "$msg" >> "$LOG_FILE" +print_error() { + echo -e "${RED}✗${NC} $1" >&2 + log_message "$1" "ERROR" } -# Fonction pour vérifier si une tâche a déjà été exécutée (idempotence) -is_task_done() { - local task_name="$1" - [[ -f "${STATE_DIR}/${task_name}.done" ]] +print_info() { + echo -e "${BLUE}ℹ${NC} $1" + log_message "$1" "INFO" } -# Marquer une tâche comme terminée -mark_task_done() { - local task_name="$1" - mkdir -p "$STATE_DIR" - touch "${STATE_DIR}/${task_name}.done" - echo "$(date '+%Y-%m-%d %H:%M:%S')" > "${STATE_DIR}/${task_name}.timestamp" +check_step_done() { + grep -q "^${1}$" "$STATUS_FILE" 2>/dev/null } -# Réinitialiser l'état d'une tâche -reset_task() { - local task_name="$1" - rm -f "${STATE_DIR}/${task_name}.done" "${STATE_DIR}/${task_name}.timestamp" +mark_step_done() { + echo "$1" >> "$STATUS_FILE" + log_message "Étape '$1' marquée comme terminée" "STATUS" } -# Exécuter une tâche de manière idempotente -run_task() { - local task_name="$1" - local task_function="$2" - local force="${3:-false}" +skip_step() { + print_info "Étape déjà effectuée : $1" + CURRENT_STEP=$((CURRENT_STEP + 1)) +} + +detect_container() { + grep -qE "lxc|container" /proc/self/cgroup 2>/dev/null || \ + [[ -f /.dockerenv ]] || [[ -d /dev/lxc ]] +} + +backup_file() { + local file_path="$1" + [[ -f "$file_path" ]] && { + mkdir -p "$BACKUP_DIR" + cp "$file_path" "${BACKUP_DIR}/" + log_message "Sauvegarde de $file_path" "BACKUP" + } +} + +add_unique_line() { + local line="$1" + local file="$2" + grep -qF "$line" "$file" 2>/dev/null || { + echo "$line" >> "$file" + log_message "Ajout ligne: '$line' -> $file" "CONFIG" + } +} + +update_config_value() { + local file="$1" + local key="$2" + local value="$3" + backup_file "$file" - if is_task_done "$task_name" && [[ "$force" != "true" ]]; then - info "Tâche '$task_name' déjà effectuée - ignorée (utilisez --force pour réexécuter)" - return 0 - fi - - log "Exécution de la tâche: $task_name" - if $task_function; then - mark_task_done "$task_name" - success "Tâche '$task_name' terminée avec succès" - return 0 + if grep -q "^${key}" "$file"; then + sed -i "s/^${key}.*/${key} ${value}/" "$file" else - error "Échec de la tâche '$task_name'" - return 1 + echo "${key} ${value}" >> "$file" fi } -# Gestion du verrou pour éviter les exécutions simultanées -acquire_lock() { - exec 200>"$LOCK_FILE" - if ! flock -n 200; then - error "Une autre instance du script est en cours d'exécution" - exit 1 - fi +# ============================================================================== +# FONCTIONS DE DURCISSEMENT +# ============================================================================== + +# ÉTAPE 1: Mise à jour système et installation outils +install_security_tools() { + local step_name="install_security_tools" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Mise à jour système et installation outils de sécurité" + + print_info "Mise à jour des dépôts..." + DEBIAN_FRONTEND=noninteractive apt-get update -qq + + print_info "Mise à jour du système..." + DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq + + local packages="lynis aide aide-common fail2ban ufw libpam-pwquality apt-listchanges \ + apt-listbugs needrestart clamav clamav-daemon chrony chkrootkit \ + libpam-tmpdir debsums unattended-upgrades" + + detect_container || packages+=" acct" + + print_info "Installation des paquets de sécurité..." + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq $packages + + print_success "Système mis à jour et outils installés" + mark_step_done "$step_name" } -release_lock() { - flock -u 200 - rm -f "$LOCK_FILE" -} - -# Nettoyage amélioré -cleanup() { - error "Script interrompu. Nettoyage en cours..." - release_lock - exit 1 -} - -trap cleanup INT TERM EXIT - -# ============================================================================ -# VÉRIFICATIONS PRÉLIMINAIRES -# ============================================================================ - -check_root() { - if [[ $EUID -ne 0 ]]; then - error "Ce script doit être exécuté en tant que root (sudo ./script.sh)" - exit 1 - fi -} - -check_distribution() { - if [[ -f /etc/os-release ]]; then - source /etc/os-release - info "Distribution détectée: $PRETTY_NAME" - - if [[ "$ID_LIKE" =~ (debian|ubuntu) ]] || [[ "$ID" =~ (debian|ubuntu) ]]; then - return 0 - fi +# ÉTAPE 2: 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 + print_warning "Conteneur détecté - Process Accounting désactivé" + for service in acct.service psacct.service; do + systemctl list-unit-files | grep -q "^${service}" && { + systemctl stop "$service" 2>/dev/null || true + systemctl disable "$service" 2>/dev/null || true + systemctl mask "$service" 2>/dev/null || true + } + done + else + systemctl enable acct.service 2>/dev/null && \ + systemctl start acct.service 2>/dev/null && \ + print_success "Process Accounting activé" || \ + print_warning "Process Accounting non disponible" fi - error "Ce script est conçu pour les distributions basées sur Debian/Ubuntu" - exit 1 + mark_step_done "$step_name" } -check_disk_space() { - local required_space=1048576 # 1GB en KB - local available_space=$(df / | awk 'NR==2 {print $4}') +# ÉTAPE 3: Durcissement sysctl +configure_sysctl_security() { + local step_name="configure_sysctl_security" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - if [[ $available_space -lt $required_space ]]; then - error "Espace disque insuffisant. Requis: 1GB, Disponible: $((available_space/1024))MB" - exit 1 - fi -} + 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 +net.ipv4.conf.all.log_martians = 1 +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.accept_source_route = 0 +net.ipv4.conf.default.accept_redirects = 0 +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 -check_internet_connectivity() { - if ! ping -c 1 -W 2 8.8.8.8 &> /dev/null; then - warn "Pas de connectivité Internet détectée. Certaines opérations peuvent échouer." - read -p "Continuer quand même? (y/N) " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - exit 1 - fi - fi -} +# 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 -# ============================================================================ -# SAUVEGARDE ET RESTAURATION -# ============================================================================ +# 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 -backup_configs() { - local backup_dir="${BACKUP_BASE_DIR}_$(date +%Y%m%d_%H%M%S)" - - if is_task_done "backup_configs"; then - info "Sauvegarde déjà effectuée" - return 0 - fi - - log "Sauvegarde des fichiers de configuration..." - mkdir -p "$backup_dir" - - local files=( - "/etc/ssh/sshd_config" - "/etc/login.defs" - "/etc/pam.d/common-password" - "/etc/pam.d/common-auth" - "/etc/security/limits.conf" - "/etc/sysctl.conf" - "/etc/fstab" - "/etc/default/grub" - "/etc/audit/auditd.conf" - "/etc/rsyslog.conf" - ) - - for file in "${files[@]}"; do - if [[ -f "$file" ]]; then - cp -p "$file" "$backup_dir/" 2>/dev/null || warn "Impossible de sauvegarder $file" - fi - done - - # Sauvegarder la liste des paquets installés - dpkg --get-selections > "$backup_dir/installed_packages.list" - - # Sauvegarder les règles UFW - if command -v ufw &> /dev/null; then - ufw status numbered > "$backup_dir/ufw_rules.txt" 2>/dev/null || true - fi - - # Sauvegarder les services actifs - systemctl list-units --type=service --state=running > "$backup_dir/active_services.txt" - - # Créer un fichier de métadonnées - cat > "$backup_dir/metadata.txt" < "${STATE_DIR}/last_backup_dir" + sysctl -p /etc/sysctl.d/99-security-hardening.conf 2>/dev/null || \ + print_warning "Certains paramètres sysctl ignorés" + + print_success "Paramètres sysctl appliqués" + mark_step_done "$step_name" } -# ============================================================================ -# MISE À JOUR ET INSTALLATION -# ============================================================================ +# ÉTAPE 4: Configuration permissions logs +configure_log_permissions() { + local step_name="configure_log_permissions" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration des permissions des fichiers de log" + + find /var/log -type f -exec chmod 640 {} \; 2>/dev/null || true + [[ -f /var/log/auth.log ]] && chmod 600 /var/log/auth.log + [[ -f /var/log/syslog ]] && chmod 600 /var/log/syslog + chown root:adm /var/log/ 2>/dev/null || true + chmod 750 /var/log/ 2>/dev/null || true + + print_success "Permissions des logs configurées" + mark_step_done "$step_name" +} -update_system() { - log "Mise à jour du système..." - export DEBIAN_FRONTEND=noninteractive +# ÉTAPE 5: Politique mots de passe PAM +configure_pam_password_policy() { + local step_name="configure_pam_password_policy" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - # Nettoyer les verrous APT si nécessaire - rm -f /var/lib/apt/lists/lock - rm -f /var/cache/apt/archives/lock - rm -f /var/lib/dpkg/lock* + print_step "Configuration de la politique de mots de passe PAM" - # Configurer dpkg pour éviter les prompts - dpkg --configure -a + backup_file "/etc/security/pwquality.conf" - apt update -qq || { - error "Échec de la mise à jour des dépôts" + cat >> /etc/security/pwquality.conf << 'EOF' + +# Configuration renforcée +minlen = 14 +minclass = 3 +maxrepeat = 3 +maxsequence = 3 +dcredit = -1 +ucredit = -1 +lcredit = -1 +ocredit = -1 +difok = 3 +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 + + print_success "Politique PAM configurée" + mark_step_done "$step_name" +} + +# ÉTAPE 6: Configuration login.defs +configure_login_defs() { + local step_name="configure_login_defs" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration des paramètres de connexion (login.defs)" + + backup_file "/etc/login.defs" + + update_config_value "/etc/login.defs" "PASS_MAX_DAYS" "90" + update_config_value "/etc/login.defs" "PASS_MIN_DAYS" "7" + update_config_value "/etc/login.defs" "PASS_WARN_AGE" "7" + update_config_value "/etc/login.defs" "LOGIN_RETRIES" "3" + update_config_value "/etc/login.defs" "LOGIN_TIMEOUT" "60" + update_config_value "/etc/login.defs" "UMASK" "027" + update_config_value "/etc/login.defs" "ENCRYPT_METHOD" "SHA512" + update_config_value "/etc/login.defs" "SHA_CRYPT_MIN_ROUNDS" "500000" + update_config_value "/etc/login.defs" "SHA_CRYPT_MAX_ROUNDS" "1000000" + + print_success "Configuration login.defs appliquée" + mark_step_done "$step_name" +} + +# ÉTAPE 7: Configuration umask global +configure_umask() { + local step_name="configure_umask" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration de l'umask par défaut" + + for file in /etc/profile /etc/bash.bashrc; do + backup_file "$file" + sed -i '/^umask/d' "$file" + add_unique_line "umask 027" "$file" + done + + print_success "Umask configuré à 027" + mark_step_done "$step_name" +} + +# ÉTAPE 8: Configuration AIDE SHA512 +configure_aide_sha512() { + local step_name="configure_aide_sha512" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration AIDE pour SHA512" + + backup_file "/etc/aide/aide.conf" + + grep -q "ALLXTRAHASHES" /etc/aide/aide.conf && \ + sed -i 's/ALLXTRAHASHES.*=.*/ALLXTRAHASHES = sha512/' /etc/aide/aide.conf || \ + echo "ALLXTRAHASHES = sha512" >> /etc/aide/aide.conf + + print_success "AIDE configuré pour SHA512" + mark_step_done "$step_name" +} + +# ÉTAPE 9: Initialisation AIDE +initialize_aide_db() { + local step_name="initialize_aide_db" + 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 (peut prendre plusieurs minutes)..." + + if command -v aideinit > /dev/null; then + aideinit && print_success "Base de données AIDE initialisée via aideinit" || { + print_error "Échec aideinit" + return 1 + } + else + aide --init --config /etc/aide/aide.conf && { + [[ -f /var/lib/aide/aide.db.new ]] && { + mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db + print_success "Base de données AIDE initialisée" + } || { + print_error "Fichier de base de données non trouvé" + return 1 + } + } || { + print_error "Échec initialisation AIDE" + return 1 + } + fi + + mark_step_done "$step_name" +} + +# ÉTAPE 10: Configuration ClamAV +configure_clamav() { + local step_name="configure_clamav" + 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 (normal si déjà récent)" + + systemctl enable clamav-freshclam + systemctl start clamav-freshclam + systemctl enable clamav-daemon 2>/dev/null || true + systemctl start clamav-daemon 2>/dev/null || true + + print_success "ClamAV configuré" + mark_step_done "$step_name" +} + +# ÉTAPE 11: Configuration Chrony +configure_chrony() { + local step_name="configure_chrony" + 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é (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 - service peut-être non disponible" + fi + + mark_step_done "$step_name" +} + +# ÉTAPE 12: Durcissement SSH +harden_ssh() { + local step_name="harden_ssh" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Durcissement du service SSH" + + backup_file "/etc/ssh/sshd_config" + + 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" + } + + # Configuration des ports + sed -i '/^Port /d' "$sshd_config" + sed -i '/^#Port /d' "$sshd_config" + echo "Port 22" >> "$sshd_config" + echo "Port $NEW_SSH_PORT" >> "$sshd_config" + + # 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" + update_ssh_param "PermitEmptyPasswords" "no" "$sshd_config" + update_ssh_param "X11Forwarding" "no" "$sshd_config" + update_ssh_param "MaxAuthTries" "3" "$sshd_config" + update_ssh_param "ClientAliveInterval" "300" "$sshd_config" + update_ssh_param "ClientAliveCountMax" "2" "$sshd_config" + update_ssh_param "LoginGraceTime" "60" "$sshd_config" + update_ssh_param "MaxSessions" "2" "$sshd_config" + update_ssh_param "TCPKeepAlive" "no" "$sshd_config" + update_ssh_param "AllowAgentForwarding" "no" "$sshd_config" + update_ssh_param "AllowTcpForwarding" "no" "$sshd_config" + update_ssh_param "LogLevel" "VERBOSE" "$sshd_config" + 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" + print_warning "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_warning "⚠ TESTEZ IMMÉDIATEMENT dans un NOUVEAU terminal:" + print_warning " ssh -p $NEW_SSH_PORT $(whoami)@$(hostname -I | awk '{print $1}')" + print_warning " NE FERMEZ PAS cette session avant validation!" + print_warning "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + else + print_error "Échec redémarrage SSH" + print_error "Restauration de la configuration..." + cp "${BACKUP_DIR}/sshd_config" /etc/ssh/sshd_config + systemctl restart sshd 2>/dev/null || systemctl restart ssh 2>/dev/null + return 1 + fi + else + print_error "Configuration SSH invalide - vérifiez les logs" + print_error "Restauration de la sauvegarde..." + cp "${BACKUP_DIR}/sshd_config" /etc/ssh/sshd_config + return 1 + fi + + mark_step_done "$step_name" +} + +# ÉTAPE 13: Configuration bannières +configure_banners() { + local step_name="configure_banners" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration des bannières légales" + + local banner_text="╔════════════════════════════════════════════════════════════╗ +║ SYSTÈME SÉCURISÉ ║ +║ ║ +║ Accès réservé aux personnes autorisées uniquement. ║ +║ Toute tentative d'accès non autorisée est interdite ║ +║ et sera tracée et poursuivie selon la loi. ║ +║ ║ +║ Les activités sont surveillées et enregistrées. ║ +╚════════════════════════════════════════════════════════════╝" + + echo "$banner_text" | tee /etc/issue /etc/issue.net /etc/motd > /dev/null + + print_success "Bannières légales configurées" + mark_step_done "$step_name" +} + +# ÉTAPE 14: Configuration UFW +configure_ufw_firewall() { + local step_name="configure_ufw_firewall" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration du pare-feu UFW" + + # 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" + print_info "Les règles de pare-feu doivent être configurées au niveau de l'hôte" + + # 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 } - apt upgrade -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" - apt autoremove -y -qq - apt autoclean -qq + print_info "Configuration des politiques par défaut..." + ufw default deny incoming + ufw default allow outgoing - # Mettre à jour la base de données locate si présente - command -v updatedb &> /dev/null && updatedb || true -} + # Ports SSH + print_info "Autorisation des ports SSH..." + ufw allow 22/tcp comment 'SSH temporaire' || print_warning "Erreur ajout règle SSH:22" + ufw allow "${NEW_SSH_PORT}/tcp" comment 'SSH sécurisé' || print_warning "Erreur ajout règle SSH:${NEW_SSH_PORT}" + + # Limiter ICMP + print_info "Configuration limitation ICMP..." + if [[ -f /etc/ufw/before.rules ]]; then + backup_file "/etc/ufw/before.rules" + + # Vérifier si la règle n'existe pas déjà + if ! grep -q "Limiter pings" /etc/ufw/before.rules; then + cat >> /etc/ufw/before.rules << 'EOF' -install_security_tools() { - log "Installation des outils de durcissement..." - - local packages=( - # Outils de sécurité - lynis fail2ban ufw aide aide-common - # Antivirus - clamav clamav-daemon clamav-freshclam - # Détection rootkit - chkrootkit rkhunter - # Audit et logging - auditd audispd-plugins - rsyslog logwatch logrotate - # Authentification - libpam-tmpdir libpam-pwquality libpam-cracklib - # Monitoring - sysstat iotop htop - # Outils réseau - net-tools tcpdump nmap - # Synchronisation temps - chrony - # Détection d'intrusion - psad - # Autres - debsums apt-listchanges unattended-upgrades - acct apparmor apparmor-utils apparmor-profiles - tiger needrestart debsecan - ) - - local failed_packages=() - - export DEBIAN_FRONTEND=noninteractive - - for package in "${packages[@]}"; do - if ! dpkg -l | grep -q "^ii $package "; then - if apt install -y -qq -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" "$package" 2>/dev/null; then - info "✓ $package installé" - else - warn "✗ Échec de l'installation de $package" - failed_packages+=("$package") - fi - else - info "✓ $package déjà installé" +# Limiter pings +-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 - done - - if [[ ${#failed_packages[@]} -gt 0 ]]; then - warn "Paquets non installés: ${failed_packages[*]}" fi + + # Activer UFW + 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é" + else + # Fallback + 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 + + mark_step_done "$step_name" } -# ============================================================================ -# CONFIGURATION FAIL2BAN -# ============================================================================ - +# ÉTAPE 15: Configuration Fail2ban configure_fail2ban() { - log "Configuration de Fail2ban..." + local step_name="configure_fail2ban" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - # Configuration locale qui ne sera pas écrasée - cat > /etc/fail2ban/jail.local < /etc/fail2ban/jail.local << EOF [DEFAULT] -# Ignorer les adresses locales et les réseaux de confiance -ignoreip = 127.0.0.1/8 ::1 -# Ajouter vos IPs de confiance ici: 192.168.1.0/24 - -# Durée de bannissement (en secondes) -bantime = 3600 -findtime = 600 +bantime = 1h +findtime = 10m maxretry = 3 +ignoreip = 127.0.0.1/8 ::1 +backend = systemd -# Action par défaut -banaction = ufw -banaction_allports = ufw - -# Email (optionnel) -# destemail = admin@example.com -# sendername = Fail2Ban -# mta = sendmail +# Mode conteneur - pas d'action iptables +banaction = %(banaction_allports)s +banaction_allports = iptables-multiport [sshd] enabled = true -port = ${SSH_PORT} +port = 22,${NEW_SSH_PORT} +filter = sshd logpath = /var/log/auth.log -maxretry = 3 -findtime = 600 -bantime = 7200 - -[sshd-ddos] -enabled = true -port = ${SSH_PORT} -logpath = /var/log/auth.log -maxretry = 6 -findtime = 600 -bantime = 600 - -[recidive] -enabled = true -logpath = /var/log/fail2ban.log -bantime = 86400 -findtime = 86400 -maxretry = 3 +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 (logging seul, sans bannissement iptables)" + else + # Configuration complète pour système physique/VM + cat > /etc/fail2ban/jail.local << EOF +[DEFAULT] +bantime = 1h +findtime = 10m +maxretry = 3 +ignoreip = 127.0.0.1/8 ::1 +backend = systemd - # Ajouter des filtres pour Apache si installé - if systemctl is-active --quiet apache2 2>/dev/null; then - cat >> /etc/fail2ban/jail.local </dev/null; then - cat >> /etc/fail2ban/jail.local <&1 | tee -a "$LOG_FILE" || true - # Ajouter des filtres pour Postfix si installé - if systemctl is-active --quiet postfix 2>/dev/null; then - cat >> /etc/fail2ban/jail.local < /dev/null; then - systemctl enable fail2ban - systemctl restart fail2ban - success "Fail2ban configuré et démarré" - else - error "Erreur dans la configuration Fail2ban" - return 1 - fi -} - -# ============================================================================ -# CONFIGURATION UFW (PARE-FEU) -# ============================================================================ - -configure_ufw() { - log "Configuration du pare-feu UFW..." - - # Sauvegarder les règles actuelles si UFW est déjà actif - if ufw status | grep -q "Status: active"; then - ufw status numbered > "${STATE_DIR}/ufw_backup_$(date +%Y%m%d_%H%M%S).txt" - fi - - # Désactiver UFW temporairement - ufw --force disable - - # Réinitialiser SEULEMENT si pas déjà configuré - if [[ ! -f "${STATE_DIR}/ufw_configured" ]]; then - ufw --force reset - fi - - # Politique par défaut - ufw default deny incoming - ufw default allow outgoing - ufw default deny forward - - # Autoriser le loopback - ufw allow in on lo - ufw allow out on lo - - # SSH sur port personnalisé - ufw allow ${SSH_PORT}/tcp comment 'SSH Custom Port' - - # Services web (commentés par défaut) - # ufw allow 80/tcp comment 'HTTP' - # ufw allow 443/tcp comment 'HTTPS' - - # DNS (sortant seulement, entrant généralement pas nécessaire) - ufw allow out 53 comment 'DNS' - - # NTP - ufw allow out 123/udp comment 'NTP' - - # Protection contre les scans de ports - ufw limit ${SSH_PORT}/tcp - - # Logging - ufw logging medium - - # Activer UFW - ufw --force enable - - touch "${STATE_DIR}/ufw_configured" - - # Afficher les règles - ufw status verbose -} - -# ============================================================================ -# CONFIGURATION SSH SÉCURISÉE -# ============================================================================ - -configure_ssh() { - log "Configuration sécurisée de SSH..." - - # Vérifier si des clés SSH existent pour les utilisateurs - local has_ssh_keys=false - for user_home in /home/*; do - if [[ -f "$user_home/.ssh/authorized_keys" ]] && [[ -s "$user_home/.ssh/authorized_keys" ]]; then - has_ssh_keys=true - break + 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)" + else + print_warning "Fail2ban démarré mais statut incertain" fi + else + print_warning "Problème au démarrage de Fail2ban - vérifiez les logs: journalctl -xeu fail2ban" + fi + + mark_step_done "$step_name" +} + +# ÉTAPE 16: Suppression paquets inutiles +remove_unneeded_packages() { + local step_name="remove_unneeded_packages" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Suppression des paquets inutiles" + + local packages_to_remove=(telnet rsh-client rsh-server netcat-openbsd netcat-traditional nis talk talkd) + + for package in "${packages_to_remove[@]}"; do + dpkg -l | grep -q "^ii.*${package}" && { + DEBIAN_FRONTEND=noninteractive apt-get purge -y -qq "$package" 2>/dev/null + print_info "Paquet $package supprimé" + } done - if [[ "$has_ssh_keys" == "false" ]]; then - warn "ATTENTION: Aucune clé SSH trouvée pour les utilisateurs !" - warn "L'authentification par mot de passe SSH sera DÉSACTIVÉE." - read -p "Continuer? Vous pourriez perdre l'accès SSH! (y/N) " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - error "Configuration SSH annulée. Configurez d'abord vos clés SSH." - return 1 - fi - fi + DEBIAN_FRONTEND=noninteractive apt-get autoremove -y -qq - # Sauvegarder la config actuelle si pas déjà fait - [[ ! -f /etc/ssh/sshd_config.bak ]] && cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - - # Configuration SSH durcie - cat > /etc/ssh/sshd_config < /etc/issue.net <<'EOF' -################################################################################ -# # -# SYSTÈME SÉCURISÉ - ACCÈS RESTREINT # -# # -# Ce système est réservé exclusivement aux utilisateurs autorisés. # -# Toutes les connexions et activités sont surveillées et enregistrées. # -# L'accès non autorisé est strictement interdit et sera poursuivi. # -# # -# Si vous n'êtes pas autorisé, déconnectez-vous immédiatement. # -# # -################################################################################ -EOF - - # Appliquer aussi la bannière au login local - cp /etc/issue.net /etc/issue - - # Vérifier et appliquer la configuration - if sshd -t 2>/dev/null; then - systemctl restart sshd - success "Configuration SSH appliquée - Port: ${SSH_PORT}" - info "Testez votre connexion SSH sur le port ${SSH_PORT} AVANT de fermer cette session!" - else - error "Erreur dans la configuration SSH!" - sshd -t - return 1 - fi + print_success "Paquets inutiles supprimés" + mark_step_done "$step_name" } -# ============================================================================ -# CONFIGURATION SYSCTL (KERNEL) -# ============================================================================ - -configure_sysctl() { - log "Configuration des paramètres kernel (sysctl)..." +# ÉTAPE 17: Restriction permissions +restrict_file_permissions() { + local step_name="restrict_file_permissions" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - # Créer un fichier de configuration dédié - cat > /etc/sysctl.d/99-hardening.conf <<'EOF' -# Configuration de sécurité kernel - Hardening Script -# Généré automatiquement + print_step "Restriction des permissions des fichiers critiques" + + chmod 644 /etc/passwd 2>/dev/null || true + chmod 600 /etc/shadow 2>/dev/null || true + chmod 644 /etc/group 2>/dev/null || true + chmod 600 /etc/gshadow 2>/dev/null || true + chmod 600 /etc/sudoers 2>/dev/null || true + chmod 750 /etc/sudoers.d 2>/dev/null || true + chmod 600 /boot/grub/grub.cfg 2>/dev/null || true + chmod 644 /etc/ssh/ssh_config 2>/dev/null || true + chmod 600 /etc/ssh/sshd_config 2>/dev/null || true + + print_success "Permissions des fichiers critiques restreintes" + mark_step_done "$step_name" +} -# ============================================================================ -# SÉCURITÉ RÉSEAU IPv4 -# ============================================================================ +# ÉTAPE 18: Désactivation modules noyau +disable_risky_kernel_modules() { + local step_name="disable_risky_kernel_modules" + 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 +install sctp /bin/true +blacklist rds +install rds /bin/true +blacklist tipc +install tipc /bin/true -# Protection contre IP spoofing (vérification de la source) -net.ipv4.conf.default.rp_filter = 1 -net.ipv4.conf.all.rp_filter = 1 +# Systèmes de fichiers non utilisés +blacklist cramfs +install cramfs /bin/true +blacklist freevxfs +install freevxfs /bin/true +blacklist jffs2 +install jffs2 /bin/true +blacklist hfs +install hfs /bin/true +blacklist hfsplus +install hfsplus /bin/true +blacklist squashfs +install squashfs /bin/true +blacklist udf +install udf /bin/true -# Ignorer les pings ICMP (protection contre ping flood) -net.ipv4.icmp_echo_ignore_all = 1 -net.ipv4.icmp_ignore_bogus_error_responses = 1 +# FireWire (DMA attack) +blacklist firewire-core +install firewire-core /bin/true -# Ignorer les redirections ICMP -net.ipv4.conf.all.accept_redirects = 0 -net.ipv4.conf.default.accept_redirects = 0 -net.ipv4.conf.all.secure_redirects = 0 -net.ipv4.conf.default.secure_redirects = 0 - -# Ne pas envoyer de redirections ICMP -net.ipv4.conf.all.send_redirects = 0 -net.ipv4.conf.default.send_redirects = 0 - -# Ignorer les paquets source routed -net.ipv4.conf.all.accept_source_route = 0 -net.ipv4.conf.default.accept_source_route = 0 - -# Protection SYN flood -net.ipv4.tcp_syncookies = 1 -net.ipv4.tcp_max_syn_backlog = 2048 -net.ipv4.tcp_synack_retries = 2 -net.ipv4.tcp_syn_retries = 5 - -# Désactiver le routage IP si non routeur -net.ipv4.ip_forward = 0 -net.ipv4.conf.all.forwarding = 0 -net.ipv4.conf.default.forwarding = 0 - -# Log des paquets suspects -net.ipv4.conf.all.log_martians = 1 -net.ipv4.conf.default.log_martians = 1 - -# Protection contre les attaques de temps -net.ipv4.tcp_timestamps = 0 - -# Amélioration des performances TCP -net.ipv4.tcp_window_scaling = 1 -net.ipv4.tcp_sack = 1 - -# ============================================================================ -# SÉCURITÉ RÉSEAU IPv6 -# ============================================================================ - -# Désactiver IPv6 si non utilisé (décommenter si nécessaire) -# net.ipv6.conf.all.disable_ipv6 = 1 -# net.ipv6.conf.default.disable_ipv6 = 1 -# net.ipv6.conf.lo.disable_ipv6 = 1 - -# Si IPv6 est utilisé, appliquer les mêmes protections -net.ipv6.conf.all.accept_redirects = 0 -net.ipv6.conf.default.accept_redirects = 0 -net.ipv6.conf.all.accept_source_route = 0 -net.ipv6.conf.default.accept_source_route = 0 -net.ipv6.conf.all.accept_ra = 0 -net.ipv6.conf.default.accept_ra = 0 -net.ipv6.conf.all.forwarding = 0 - -# ============================================================================ -# SÉCURITÉ KERNEL -# ============================================================================ - -# Restreindre l'accès aux logs kernel -kernel.dmesg_restrict = 1 - -# Masquer les adresses kernel -kernel.kptr_restrict = 2 - -# Protection ptrace (empêche l'attachement aux processus) -kernel.yama.ptrace_scope = 1 - -# Protection contre les attaques par lien symbolique -fs.protected_symlinks = 1 -fs.protected_hardlinks = 1 - -# Protection FIFO et fichiers réguliers -fs.protected_fifos = 2 -fs.protected_regular = 2 - -# Désactiver les SysRq sauf reboot/shutdown d'urgence -kernel.sysrq = 16 - -# Limiter la visibilité des processus -# kernel.unprivileged_userns_clone = 0 - -# ============================================================================ -# AUTRES PARAMÈTRES DE SÉCURITÉ -# ============================================================================ - -# Randomisation de l'espace d'adressage -kernel.randomize_va_space = 2 - -# Core dumps -kernel.core_uses_pid = 1 -fs.suid_dumpable = 0 - -# Limite des fichiers ouverts -fs.file-max = 2097152 - -# IPC -kernel.msgmnb = 65536 -kernel.msgmax = 65536 - -# Shared memory -kernel.shmmax = 68719476736 -kernel.shmall = 4294967296 +# Thunderbolt (DMA attack) +blacklist thunderbolt +install thunderbolt /bin/true EOF - - # Appliquer immédiatement les changements - sysctl -p /etc/sysctl.d/99-hardening.conf - success "Paramètres kernel appliqués" + detect_container && \ + print_warning "Conteneur - modules gérés par l'hôte" || \ + print_info "Modules blacklistés" + + print_success "Modules noyau risqués désactivés" + mark_step_done "$step_name" } -# ============================================================================ -# POLITIQUE DE MOTS DE PASSE -# ============================================================================ +# ÉTAPE 19: Configuration limites sécurité +configure_security_limits() { + local step_name="configure_security_limits" + 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' -configure_password_policy() { - log "Configuration de la politique de mots de passe..." - - # Sauvegarde - [[ ! -f /etc/login.defs.bak ]] && cp /etc/login.defs /etc/login.defs.bak - - # Configuration login.defs (idempotent avec sed) - sed -i.tmp 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs - sed -i.tmp 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 1/' /etc/login.defs - sed -i.tmp 's/^PASS_WARN_AGE.*/PASS_WARN_AGE 14/' /etc/login.defs - sed -i.tmp 's/^UMASK.*/UMASK 027/' /etc/login.defs - sed -i.tmp 's/^ENCRYPT_METHOD.*/ENCRYPT_METHOD SHA512/' /etc/login.defs - - # Ajouter les paramètres manquants (idempotent) - grep -q "^SHA_CRYPT_MIN_ROUNDS" /etc/login.defs || echo "SHA_CRYPT_MIN_ROUNDS 5000" >> /etc/login.defs - grep -q "^SHA_CRYPT_MAX_ROUNDS" /etc/login.defs || echo "SHA_CRYPT_MAX_ROUNDS 5000" >> /etc/login.defs - grep -q "^FAILLOG_ENAB" /etc/login.defs || echo "FAILLOG_ENAB yes" >> /etc/login.defs - grep -q "^LOG_UNKFAIL_ENAB" /etc/login.defs || echo "LOG_UNKFAIL_ENAB yes" >> /etc/login.defs - - # Configuration PAM pour la qualité des mots de passe (idempotent) - if [[ -f /etc/pam.d/common-password ]]; then - [[ ! -f /etc/pam.d/common-password.bak ]] && cp /etc/pam.d/common-password /etc/pam.d/common-password.bak - - if ! grep -q "pam_pwquality.so" /etc/pam.d/common-password; then - sed -i '/pam_unix.so/i password requisite pam_pwquality.so retry=3 minlen=14 difok=4 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=2 reject_username enforce_for_root' /etc/pam.d/common-password - fi - - # Ajouter pam_pwhistory pour empêcher la réutilisation des mots de passe - if ! grep -q "pam_pwhistory.so" /etc/pam.d/common-password; then - sed -i '/pam_unix.so/a password required pam_pwhistory.so remember=5 use_authtok' /etc/pam.d/common-password - fi - fi - - # Configuration de verrouillage de compte après échecs - if [[ -f /etc/pam.d/common-auth ]]; then - [[ ! -f /etc/pam.d/common-auth.bak ]] && cp /etc/pam.d/common-auth /etc/pam.d/common-auth.bak - - if ! grep -q "pam_faillock.so" /etc/pam.d/common-auth; then - sed -i '1i auth required pam_faillock.so preauth silent audit deny=5 unlock_time=900' /etc/pam.d/common-auth - echo "auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900" >> /etc/pam.d/common-auth - echo "auth sufficient pam_faillock.so authsucc" >> /etc/pam.d/common-auth - fi - fi - - success "Politique de mots de passe configurée" -} - -# ============================================================================ -# LIMITES SYSTÈME -# ============================================================================ - -configure_limits() { - log "Configuration des limites système..." - - [[ ! -f /etc/security/limits.conf.bak ]] && cp /etc/security/limits.conf /etc/security/limits.conf.bak - - # Ajouter les limites si elles n'existent pas déjà - if ! grep -q "# Hardening Script Limits" /etc/security/limits.conf; then - cat >> /etc/security/limits.conf <<'EOF' - -# Hardening Script Limits -# Core dumps désactivés pour tous +# Désactiver core dumps * hard core 0 -* soft core 0 -# Limites de processus -* soft nproc 65536 -* hard nproc 65536 +# Limiter les processus +* soft nproc 512 +* hard nproc 1024 -# Limites de fichiers ouverts +# Limiter les fichiers ouverts * soft nofile 65536 * hard nofile 65536 - -# Stack size -* hard stack 2048 - -# Root illimité pour les processus -root soft nproc unlimited -root hard nproc unlimited EOF - fi - success "Limites système configurées" + print_success "Limites de sécurité configurées" + mark_step_done "$step_name" } -# ============================================================================ -# DÉSACTIVATION DES MODULES ET SERVICES -# ============================================================================ - -disable_unnecessary_services() { - log "Désactivation des services et modules non nécessaires..." +# ÉTAPE 20: Vérification intégrité paquets +verify_packages_integrity() { + local step_name="verify_packages_integrity" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - # Désactiver les modules noyau dangereux - cat > /etc/modprobe.d/hardening-disable-modules.conf <<'EOF' -# Désactivation des protocoles réseau non nécessaires -install dccp /bin/true -install sctp /bin/true -install tipc /bin/true -install rds /bin/true + print_step "Vérification de l'intégrité des paquets" + + 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" +} -# Désactivation des systèmes de fichiers rares -install cramfs /bin/true -install freevxfs /bin/true -install jffs2 /bin/true -install hfs /bin/true -install hfsplus /bin/true -install squashfs /bin/true -install udf /bin/true -install vfat /bin/true +# ÉTAPE 21: Configuration mises à jour auto +configure_automatic_updates() { + local step_name="configure_automatic_updates" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration des mises à jour automatiques" + + cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF' +Unattended-Upgrade::Allowed-Origins { + "${distro_id}:${distro_codename}-security"; + "${distro_id}:${distro_codename}-updates"; +}; -# Désactivation des modules sans fil et bluetooth -blacklist firewire-core -blacklist thunderbolt -blacklist bluetooth -blacklist btusb -blacklist bnep - -# Désactivation USB (décommenter si serveur sans USB) -# blacklist usb-storage -# blacklist uas - -# Désactivation de modules anciens -blacklist floppy +Unattended-Upgrade::AutoFixInterruptedDpkg "true"; +Unattended-Upgrade::MinimalSteps "true"; +Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +Unattended-Upgrade::Automatic-Reboot "false"; +Unattended-Upgrade::Automatic-Reboot-Time "04:00"; +Unattended-Upgrade::Mail "root"; +Unattended-Upgrade::MailReport "on-change"; EOF - - # Liste des services à désactiver (si présents) - local services_to_disable=( - bluetooth.service - cups.service - cups-browsed.service - avahi-daemon.service - avahi-daemon.socket - rpcbind.service - rpcbind.socket - nfs-common.service - nfs-kernel-server.service - iscsid.service - open-iscsi.service - snapd.service - snapd.socket - ) - for service in "${services_to_disable[@]}"; do - if systemctl list-unit-files | grep -q "^${service}"; then - if systemctl is-enabled "$service" &>/dev/null; then - systemctl disable "$service" 2>/dev/null || true - systemctl stop "$service" 2>/dev/null || true - info "✓ Service désactivé: $service" + cat > /etc/apt/apt.conf.d/10periodic << 'EOF' +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Download-Upgradeable-Packages "1"; +APT::Periodic::AutocleanInterval "7"; +APT::Periodic::Unattended-Upgrade "1"; +EOF + + print_success "Mises à jour automatiques configurées" + mark_step_done "$step_name" +} + +# ÉTAPE 22: Configuration tâche AIDE cron +configure_aide_cron() { + local step_name="configure_aide_cron" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Configuration des vérifications AIDE planifiées" + + cat > /etc/cron.weekly/aide-check << 'EOF' +#!/bin/bash +LOGFILE="/var/log/aide-check-$(date +%Y%m%d).log" + +if command -v aide > /dev/null; then + echo "=== Vérification AIDE $(date) ===" > "$LOGFILE" + + if /usr/bin/aide --check >> "$LOGFILE" 2>&1; then + echo "Vérification réussie" >> "$LOGFILE" + + if grep -q "added\|changed\|removed" "$LOGFILE"; then + mail -s "[AIDE] Changements détectés sur $(hostname)" root < "$LOGFILE" + fi + else + echo "Échec vérification" >> "$LOGFILE" + mail -s "[AIDE] ALERTE - Échec sur $(hostname)" root < "$LOGFILE" + fi + + echo "=== Fin vérification $(date) ===" >> "$LOGFILE" +fi +EOF + + chmod 750 /etc/cron.weekly/aide-check + + print_success "Vérification AIDE hebdomadaire configurée" + mark_step_done "$step_name" +} + +# ÉTAPE 23: Durcissement bannière SMTP +harden_smtp_banner() { + local step_name="harden_smtp_banner" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Durcissement bannière SMTP" + + if dpkg -l | grep -q "^ii.*postfix"; then + backup_file "/etc/postfix/main.cf" + postconf -e "smtpd_banner = \$myhostname ESMTP" + postconf -e "disable_vrfy_command = yes" + systemctl reload postfix 2>/dev/null || true + print_success "Bannière Postfix durcie" + elif dpkg -l | grep -q "^ii.*exim4"; then + backup_file "/etc/exim4/exim4.conf.template" + sed -i 's/^smtp_banner.*/smtp_banner = "${primary_hostname} ESMTP"/' \ + /etc/exim4/exim4.conf.template 2>/dev/null || true + update-exim4.conf 2>/dev/null || true + print_success "Bannière Exim4 durcie" + else + print_info "Aucun serveur SMTP détecté" + fi + + mark_step_done "$step_name" +} + +# ÉTAPE 24: Durcissement services systemd +harden_systemd_services() { + local step_name="harden_systemd_services" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } + + print_step "Durcissement services systemd" + + command -v systemd-analyze > /dev/null || { + print_warning "systemd-analyze non disponible" + mark_step_done "$step_name" + 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" + local override_dir="/etc/systemd/system/${unit}.d" + + if [[ -d "$override_dir" ]]; then + print_info "Nettoyage des overrides systemd pour $unit" + rm -rf "$override_dir" + fi + done + + systemctl daemon-reload + 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 && \ + ! systemctl is-active "$unit" > /dev/null 2>&1; then + print_info "Service $unit non actif - ignoré" + continue + fi + + 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 +PrivateTmp=yes +ProtectSystem=full +ProtectHome=read-only +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +RestrictRealtime=yes +EOF + else + # Configuration standard pour les autres services + cat > "/etc/systemd/system/${unit}.d/security.conf" << EOF +[Service] +NoNewPrivileges=yes +PrivateTmp=yes +ProtectSystem=strict +ProtectHome=yes +ReadWritePaths=/var/log /var/lib/${service} /run/${service} +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +RestrictRealtime=yes +RestrictSUIDSGID=yes +EOF + fi + + hardened=$((hardened + 1)) + 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" + if systemctl list-unit-files | grep -q "^${unit}"; then + if systemctl is-active --quiet "$unit" 2>/dev/null; then + systemctl restart "$unit" 2>&1 | tee -a "$LOG_FILE" || { + print_error "Échec redémarrage $unit - restauration configuration" + rm -rf "/etc/systemd/system/${unit}.d" + systemctl daemon-reload + systemctl restart "$unit" + } fi fi done - success "Services inutiles désactivés" + print_success "$hardened service(s) systemd durci(s)" + mark_step_done "$step_name" } -# ============================================================================ -# CONFIGURATION ANTIVIRUS (CLAMAV) -# ============================================================================ - -configure_clamav() { - log "Configuration de ClamAV..." +# ÉTAPE 25: Configuration PAM avancée +configure_advanced_pam() { + local step_name="configure_advanced_pam" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - if ! command -v freshclam &> /dev/null; then - warn "ClamAV non installé, passage" - return 0 - fi + print_step "Configuration PAM avancée" - # Arrêter le service temporairement - systemctl stop clamav-freshclam 2>/dev/null || true + backup_file "/etc/pam.d/common-password" - # Configuration freshclam pour mises à jour automatiques - if [[ -f /etc/clamav/freshclam.conf ]]; then - sed -i 's/^#DatabaseMirror/DatabaseMirror/' /etc/clamav/freshclam.conf - sed -i 's/^Example/#Example/' /etc/clamav/freshclam.conf - fi - - # Mettre à jour la base de données (avec timeout) - timeout 300 freshclam || warn "Mise à jour ClamAV timeout (normal lors de la première exécution)" - - # Activer et démarrer les services - systemctl enable clamav-freshclam 2>/dev/null || true - systemctl start clamav-freshclam 2>/dev/null || true - - if systemctl list-unit-files | grep -q "clamav-daemon"; then - systemctl enable clamav-daemon 2>/dev/null || true - systemctl start clamav-daemon 2>/dev/null || true - fi - - # Créer un script de scan quotidien - cat > /etc/cron.daily/clamav-scan <<'EOF' -#!/bin/bash -SCAN_DIR="/home /var/www" -LOG_FILE="/var/log/clamav/daily-scan.log" -mkdir -p /var/log/clamav - -# Scanner les répertoires importants -clamscan -r -i --exclude-dir="^/sys" --exclude-dir="^/proc" --exclude-dir="^/dev" \ - $SCAN_DIR > "$LOG_FILE" 2>&1 - -# Envoyer un email si des virus sont détectés -if grep -q "Infected files: [1-9]" "$LOG_FILE"; then - mail -s "ClamAV: Virus détectés sur $(hostname)" root < "$LOG_FILE" -fi -EOF - chmod +x /etc/cron.daily/clamav-scan - - success "ClamAV configuré" -} - -# ============================================================================ -# CONFIGURATION AIDE (DÉTECTION D'INTRUSION) -# ============================================================================ - -configure_aide() { - log "Configuration d'AIDE (détection d'intrusion)..." - - if ! command -v aide &> /dev/null; then - warn "AIDE non installé, passage" - return 0 - fi - - # Configuration AIDE personnalisée - cat > /etc/aide/aide.conf.d/99_hardening <<'EOF' -# Configuration AIDE - Hardening Script - -# Répertoires système critiques à surveiller -/bin R+b+sha256 -/sbin R+b+sha256 -/usr/bin R+b+sha256 -/usr/sbin R+b+sha256 -/lib R+b+sha256 -/lib64 R+b+sha256 -/usr/lib R+b+sha256 -/usr/lib64 R+b+sha256 - -# Configuration système -/etc R+b+sha256 -!/etc/mtab -!/etc/adjtime - -# Fichiers de démarrage -/boot R+b+sha256 - -# Exclure les répertoires dynamiques -!/var/log -!/var/cache -!/var/tmp -!/tmp -!/proc -!/sys -!/dev -!/run -EOF - - # Initialiser la base de données AIDE (long processus) - if [[ ! -f /var/lib/aide/aide.db ]]; then - log "Initialisation de la base AIDE (peut prendre plusieurs minutes)..." - aideinit || warn "Échec de l'initialisation AIDE" + # 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 - if [[ -f /var/lib/aide/aide.db.new ]]; then - mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db - fi - fi + grep -q "rounds=" /etc/pam.d/common-password || \ + sed -i 's/pam_unix.so.*/& rounds=500000/' /etc/pam.d/common-password + } - # Script de vérification quotidienne - cat > /etc/cron.daily/aide-check <<'EOF' -#!/bin/bash -LOG_FILE="/var/log/aide/aide-check-$(date +%Y%m%d).log" -mkdir -p /var/log/aide - -# Exécuter la vérification -/usr/bin/aide --check > "$LOG_FILE" 2>&1 -EXIT_CODE=$? - -# Si des changements sont détectés (code 7) -if [[ $EXIT_CODE -eq 7 ]]; then - # Envoyer un email d'alerte - mail -s "AIDE: Modifications détectées sur $(hostname)" root < "$LOG_FILE" + # 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" ]] && \ + [[ -n "$shell" ]] && \ + [[ "$shell" != *"nologin"* ]] && \ + [[ "$shell" != *"false"* ]] && { + chage -M 90 "$user" 2>/dev/null || true + chage -d 0 "$user" 2>/dev/null || true + print_info " → $user: Expiration 90 jours configurée" + } + done < /etc/passwd - # Logger dans syslog - logger -t aide-check "ATTENTION: Modifications système détectées" -fi - -# Rotation des logs (garder 30 jours) -find /var/log/aide -name "aide-check-*.log" -mtime +30 -delete -EOF - chmod +x /etc/cron.daily/aide-check - - success "AIDE configuré" + print_success "Configuration PAM avancée appliquée" + mark_step_done "$step_name" } -# ============================================================================ -# MISES À JOUR AUTOMATIQUES -# ============================================================================ - -configure_auto_updates() { - log "Configuration des mises à jour automatiques de sécurité..." +# ÉTAPE 26: Vérification partitions +check_partition_layout() { + local step_name="check_partition_layout" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - if ! command -v unattended-upgrade &> /dev/null; then - warn "unattended-upgrades non installé, passage" - return 0 - fi + print_step "Vérification disposition partitions" - # Configuration des mises à jour automatiques - cat > /etc/apt/apt.conf.d/50unattended-upgrades <<'EOF' -Unattended-Upgrade::Allowed-Origins { - "${distro_id}:${distro_codename}-security"; - "${distro_id}ESMApps:${distro_codename}-apps-security"; - "${distro_id}ESM:${distro_codename}-infra-security"; -}; - -Unattended-Upgrade::Package-Blacklist { - // Ajouter ici les paquets à ne jamais mettre à jour automatiquement - // "mysql-server"; - // "postgresql"; -}; - -Unattended-Upgrade::DevRelease "false"; -Unattended-Upgrade::AutoFixInterruptedDpkg "true"; -Unattended-Upgrade::MinimalSteps "true"; -Unattended-Upgrade::InstallOnShutdown "false"; -Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; -Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; -Unattended-Upgrade::Remove-Unused-Dependencies "true"; -Unattended-Upgrade::Automatic-Reboot "false"; -Unattended-Upgrade::Automatic-Reboot-WithUsers "false"; -Unattended-Upgrade::Automatic-Reboot-Time "03:00"; - -Unattended-Upgrade::Mail "root"; -Unattended-Upgrade::MailReport "on-change"; - -Unattended-Upgrade::SyslogEnable "true"; -Unattended-Upgrade::SyslogFacility "daemon"; -EOF - - cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF' -APT::Periodic::Update-Package-Lists "1"; -APT::Periodic::Download-Upgradeable-Packages "1"; -APT::Periodic::Unattended-Upgrade "1"; -APT::Periodic::AutocleanInterval "7"; -APT::Periodic::Verbose "1"; -EOF - - # Tester la configuration - unattended-upgrade --dry-run --debug + local partitions=(/home /tmp /var /var/log /var/log/audit) + local warnings=() - systemctl enable unattended-upgrades - systemctl restart unattended-upgrades + for partition in "${partitions[@]}"; do + mount | grep -q " on ${partition} " && { + local device=$(mount | grep " on ${partition} " | awk '{print $1}') + print_info " ✓ $partition: Partition séparée ($device)" + } || { + warnings+=("$partition") + print_warning " ⚠ $partition: Non monté séparément" + } + done - success "Mises à jour automatiques configurées" + [[ ${#warnings[@]} -eq 0 ]] && \ + print_success "Toutes les partitions critiques séparées" || { + print_warning "${#warnings[@]} partition(s) non séparée(s)" + detect_container && \ + print_info "Conteneur: partitions gérées par l'hôte" + } + + mark_step_done "$step_name" } -# ============================================================================ -# CONFIGURATION AUDITD -# ============================================================================ - -configure_auditd() { - log "Configuration d'auditd (audit système)..." +# ÉTAPE 27: Vérification fichiers noyau +check_vmlinuz() { + local step_name="check_vmlinuz" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - if ! command -v auditctl &> /dev/null; then - warn "auditd non installé, passage" - return 0 - fi + print_step "Vérification fichiers noyau" - # Règles d'audit personnalisées - cat > /etc/audit/rules.d/hardening.rules <<'EOF' -# Règles d'audit - Hardening Script -# Supprimer toutes les règles précédentes --D - -# Buffer --b 8192 - -# Échec d'audit --f 1 - -# Surveiller les modifications de configuration --w /etc/passwd -p wa -k identity --w /etc/group -p wa -k identity --w /etc/shadow -p wa -k identity --w /etc/gshadow -p wa -k identity --w /etc/security/opasswd -p wa -k identity - -# Surveiller les modifications sudo --w /etc/sudoers -p wa -k sudoers --w /etc/sudoers.d/ -p wa -k sudoers - -# Surveiller les commandes privilégiées --a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged --a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged - -# Surveiller les modifications du système de fichiers --a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts --a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts - -# Surveiller les suppressions --a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete --a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete - -# Surveiller les changements de permissions --a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod --a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod - -# Surveiller les accès réseau --a always,exit -F arch=b64 -S socket -S connect -k network_connect --a always,exit -F arch=b32 -S socket -S connect -k network_connect - -# Surveiller les modifications de configuration réseau --w /etc/network/ -p wa -k network_modifications --w /etc/sysconfig/network-scripts/ -p wa -k network_modifications - -# Surveiller les modifications SSH --w /etc/ssh/sshd_config -p wa -k sshd_config - -# Surveiller les logs --w /var/log/wtmp -p wa -k logins --w /var/log/btmp -p wa -k logins --w /var/log/lastlog -p wa -k logins - -# Surveiller les modules kernel --w /sbin/insmod -p x -k modules --w /sbin/rmmod -p x -k modules --w /sbin/modprobe -p x -k modules - -# Rendre les règles immuables (nécessite un reboot pour changer) --e 2 -EOF - - # Recharger les règles - systemctl enable auditd - systemctl restart auditd + local files=(/vmlinuz /boot/vmlinuz "/boot/vmlinuz-$(uname -r)" "/boot/initrd.img-$(uname -r)") + local found=0 - success "Auditd configuré" + for kfile in "${files[@]}"; do + [[ -f "$kfile" ]] && { + found=$((found + 1)) + print_info " ✓ $kfile ($(du -h "$kfile" | cut -f1))" + } + done + + [[ $found -eq 0 ]] && { + print_warning "Aucun fichier noyau trouvé" + detect_container && \ + print_info "Conteneur: noyau géré par l'hôte" || { + print_error "Système physique: fichiers noyau manquants!" + apt-get install --reinstall "linux-image-$(uname -r)" 2>/dev/null || \ + print_warning "Échec réinstallation noyau" + } + } || print_success "$found fichier(s) noyau trouvé(s)" + + mark_step_done "$step_name" } -# ============================================================================ -# CONFIGURATION APPARMOR -# ============================================================================ - -configure_apparmor() { - log "Configuration d'AppArmor..." +# ÉTAPE 28: Exécution chkrootkit +run_chkrootkit() { + local step_name="run_chkrootkit" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - if ! command -v aa-status &> /dev/null; then - warn "AppArmor non installé, passage" - return 0 - fi + print_step "Exécution de chkrootkit" - # Activer AppArmor - systemctl enable apparmor - systemctl start apparmor + print_info "Scan rootkit en cours..." + chkrootkit > "$BACKUP_DIR/chkrootkit_report.log" 2>&1 || \ + print_warning "Chkrootkit a détecté des avertissements (voir $BACKUP_DIR/chkrootkit_report.log)" - # Activer tous les profils en mode enforce - aa-enforce /etc/apparmor.d/* 2>/dev/null || true - - # Afficher le statut - aa-status - - success "AppArmor configuré" + print_success "Scan chkrootkit terminé" + mark_step_done "$step_name" } -# ============================================================================ -# SÉCURISATION DU GRUB -# ============================================================================ - -secure_grub() { - log "Sécurisation du bootloader GRUB..." +# ÉTAPE 29: Nettoyage port SSH 22 temporaire +prepare_ssh_cleanup() { + local step_name="prepare_ssh_cleanup" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - if [[ ! -f /etc/default/grub ]]; then - warn "GRUB non trouvé, passage" - return 0 - fi + print_step "Préparation nettoyage port SSH 22" - [[ ! -f /etc/default/grub.bak ]] && cp /etc/default/grub /etc/default/grub.bak + print_warning "Port SSH 22 toujours actif (temporaire)" + print_info "Après avoir testé SSH sur le port $NEW_SSH_PORT:" + print_info "Exécutez: $0 --cleanup-ssh" - # Ajouter les paramètres de sécurité au kernel - if ! grep -q "GRUB_CMDLINE_LINUX.*audit=1" /etc/default/grub; then - sed -i 's/GRUB_CMDLINE_LINUX="/GRUB_CMDLINE_LINUX="audit=1 /' /etc/default/grub - fi - - # Générer un mot de passe GRUB si demandé - read -p "Voulez-vous protéger GRUB par mot de passe? (y/N) " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - log "Génération du mot de passe GRUB..." - grub-mkpasswd-pbkdf2 | tee /tmp/grub-password.txt - warn "Copiez le hash PBKDF2 et ajoutez-le manuellement dans /etc/grub.d/40_custom" - warn "Exemple: set superusers=\"root\"" - warn " password_pbkdf2 root " - fi - - # Mettre à jour GRUB - update-grub - - success "GRUB sécurisé" + mark_step_done "$step_name" } -# ============================================================================ -# SÉCURISATION DES PARTITIONS -# ============================================================================ - -secure_partitions() { - log "Vérification de la sécurisation des partitions..." +# ÉTAPE 30: Audit Lynis final +run_lynis_audit() { + local step_name="run_lynis_audit" + check_step_done "$step_name" && { skip_step "$step_name"; return 0; } - # Créer une copie de fstab - [[ ! -f /etc/fstab.bak ]] && cp /etc/fstab /etc/fstab.bak + print_step "Exécution de l'audit Lynis" - # Suggestions pour /tmp, /var/tmp, /dev/shm - info "Vérification des options de montage sécurisées..." + print_info "Audit système complet en cours (peut prendre plusieurs minutes)..." - local suggestions="" + # Exécuter Lynis et sauvegarder le rapport + lynis audit system --quick --no-colors > "$SECURITY_REPORT" 2>&1 - # Vérifier /tmp - if mount | grep -q "on /tmp "; then - if ! mount | grep "on /tmp " | grep -q "noexec"; then - suggestions+="- /tmp devrait être monté avec noexec,nodev,nosuid\n" - fi - else - suggestions+="- Envisagez de créer une partition séparée pour /tmp\n" - fi + # Extraire le score de durcissement + local score=$(grep -i "Hardening index" "$SECURITY_REPORT" | grep -oP '\d+' | head -1) + local max_score=100 # Score maximum standard Lynis - # Vérifier /var/tmp - if mount | grep -q "on /var/tmp "; then - if ! mount | grep "on /var/tmp " | grep -q "noexec"; then - suggestions+="- /var/tmp devrait être monté avec noexec,nodev,nosuid\n" - fi - fi + # Si on ne trouve pas le score dans le rapport, utiliser une valeur par défaut + [[ -z "$score" ]] && score=0 - # Vérifier /dev/shm - if ! mount | grep "on /dev/shm " | grep -q "noexec"; then - suggestions+="- /dev/shm devrait être monté avec noexec,nodev,nosuid\n" - fi + # Sauvegarder le score pour le résumé + echo "$score" > "/tmp/lynis_score.txt" + echo "$max_score" > "/tmp/lynis_max_score.txt" - # Vérifier /home - if mount | grep -q "on /home "; then - if ! mount | grep "on /home " | grep -q "nodev"; then - suggestions+="- /home devrait être monté avec nodev\n" - fi - fi + # Calculer le pourcentage pour la barre de progression + local percentage=$((score * 100 / max_score)) + 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)) - if [[ -n "$suggestions" ]]; then - warn "Suggestions de sécurisation des partitions:" - echo -e "$suggestions" - warn "Ces modifications doivent être faites manuellement dans /etc/fstab" - else - success "Partitions correctement sécurisées" - fi -} - -# ============================================================================ -# CONFIGURATION DES LOGS -# ============================================================================ - -configure_logging() { - log "Configuration avancée des logs..." + # Créer la barre de progression + local bar="[" + for ((i=0; i /etc/rsyslog.d/99-hardening.conf <<'EOF' -# Configuration rsyslog - Hardening Script - -# Logger les messages authpriv séparément -authpriv.* /var/log/auth.log - -# Logger les cron jobs -cron.* /var/log/cron.log - -# Logger les messages kernel -kern.* /var/log/kern.log - -# Logger tous les messages d'urgence -*.emerg :omusrmsg:* - -# Rotation et rétention -$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat -EOF - - systemctl restart rsyslog + # Couleur selon le score + local color=$RED + [[ $score -ge 80 ]] && color=$GREEN + [[ $score -ge 60 && $score -lt 80 ]] && color=$YELLOW - # Configuration logrotate pour conservation - cat > /etc/logrotate.d/hardening <<'EOF' -/var/log/auth.log -/var/log/cron.log -/var/log/kern.log -{ - rotate 90 - daily - missingok - notifempty - compress - delaycompress - sharedscripts - postrotate - /usr/lib/rsyslog/rsyslog-rotate - endscript -} -EOF - - success "Logging configuré" -} - -# ============================================================================ -# SCAN ET AUDIT FINAL -# ============================================================================ - -run_security_scan() { - log "Exécution du scan de sécurité final..." + print_success "Audit Lynis terminé" - local report_file="${STATE_DIR}/security_report_$(date +%Y%m%d_%H%M%S).txt" - - { - echo "==========================================" - echo "RAPPORT DE SÉCURITÉ" - echo "Date: $(date)" - echo "Hostname: $(hostname)" - echo "==========================================" - echo "" - - # Lynis - if command -v lynis &> /dev/null; then - echo "=== AUDIT LYNIS ===" - lynis audit system --quick --quiet - echo "" - fi - - # Vérification des paquets - echo "=== VÉRIFICATION INTÉGRITÉ PAQUETS ===" - debsums -s 2>&1 | head -20 - echo "" - - # Rootkit check - if command -v chkrootkit &> /dev/null; then - echo "=== SCAN ROOTKIT (chkrootkit) ===" - chkrootkit -q 2>&1 | head -20 - echo "" - fi - - if command -v rkhunter &> /dev/null; then - echo "=== SCAN ROOTKIT (rkhunter) ===" - rkhunter --check --skip-keypress --report-warnings-only 2>&1 | head -20 - echo "" - fi - - # Ports ouverts - echo "=== PORTS OUVERTS ===" - ss -tulpn - echo "" - - # Services actifs - echo "=== SERVICES ACTIFS ===" - systemctl list-units --type=service --state=running - echo "" - - # Utilisateurs avec shell - echo "=== UTILISATEURS AVEC SHELL ===" - grep -v "/nologin\|/false" /etc/passwd - echo "" - - # Dernières connexions - echo "=== DERNIÈRES CONNEXIONS ===" - last -n 20 - echo "" - - } | tee "$report_file" - - success "Rapport de sécurité généré: $report_file" -} - -# ============================================================================ -# FONCTIONS D'AIDE ET D'INFORMATION -# ============================================================================ - -show_help() { - cat </dev/null || echo "inconnue") - echo -e "${GREEN}[✓]${NC} $task (${timestamp})" + # Extraire et afficher les statistiques + echo "" + print_info "Statistiques de l'audit:" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + local warnings=$(grep -c "Warning" "$SECURITY_REPORT" 2>/dev/null || echo "0") + local suggestions=$(grep -c "Suggestion" "$SECURITY_REPORT" 2>/dev/null || echo "0") + local tests=$(grep -c "Test" "$SECURITY_REPORT" 2>/dev/null || echo "0") + + echo " • Tests effectués: $tests" + echo " • Avertissements: $warnings" + echo " • Suggestions: $suggestions" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + # Afficher les principales suggestions si score < 80 + if [[ $score -lt 80 ]]; then + echo "" + print_info "Top 5 des suggestions prioritaires:" + echo "┌──────────────────────────────────────────────────────┐" + grep "Suggestion" "$SECURITY_REPORT" | head -5 | nl -w1 -s'. ' | while read -r line; do + echo "│ ${line}" + done + echo "└──────────────────────────────────────────────────────┘" + fi + + # Afficher les warnings critiques + echo "" + if [[ $warnings -gt 0 ]]; then + print_warning "⚠ Avertissements critiques détectés:" + echo "┌──────────────────────────────────────────────────────┐" + grep "Warning" "$SECURITY_REPORT" | head -3 | nl -w1 -s'. ' | while read -r line; do + echo "│ ${line}" + done + echo "└──────────────────────────────────────────────────────┘" + fi + + echo "" + print_info "Pour voir le rapport complet: cat $SECURITY_REPORT" + print_info "Pour voir les suggestions: grep Suggestion $SECURITY_REPORT" + + mark_step_done "$step_name" +} + +# ============================================================================== +# FONCTION NETTOYAGE SSH +# ============================================================================== + +cleanup_ssh_port() { + print_step "Nettoyage définitif port SSH 22" + + echo -e "${RED}╔════════════════════════════════════════════════════════════╗${NC}" + echo -e "${RED}║ ⚠ ATTENTION CRITIQUE ⚠ ║${NC}" + echo -e "${RED}╚════════════════════════════════════════════════════════════╝${NC}" + echo "" + echo "Cette action va supprimer définitivement l'accès SSH sur le port 22." + echo "Assurez-vous d'avoir testé SSH sur le port $NEW_SSH_PORT." + echo "" + echo -n "Confirmez-vous avoir testé avec succès SSH:$NEW_SSH_PORT ? (oui/non): " + + read -r confirmation + + [[ "$confirmation" != "oui" ]] && { + print_error "Annulation. Testez d'abord: ssh -p $NEW_SSH_PORT user@$(hostname -I | awk '{print $1}')" + return 1 + } + + backup_file "/etc/ssh/sshd_config" + sed -i '/^Port 22$/d' /etc/ssh/sshd_config + ufw delete allow 22/tcp 2>/dev/null || true + + sshd -t && { + systemctl restart sshd + print_success "Port SSH 22 supprimé" + print_info "SSH disponible uniquement sur le port $NEW_SSH_PORT" + } || { + print_error "Erreur configuration - restauration" + cp "${BACKUP_DIR}/sshd_config" /etc/ssh/sshd_config + systemctl restart sshd + return 1 + } +} + +# ============================================================================== +# FONCTIONS PRINCIPALES +# ============================================================================== + +check_requirements() { + print_info "Vérification des prérequis..." + + [[ $EUID -ne 0 ]] && { + print_error "Ce script doit être exécuté en tant que root" + exit 1 + } + + [[ ! -f /etc/debian_version ]] && \ + print_warning "Système non Debian/Ubuntu - compatibilité limitée" + + mkdir -p "$BACKUP_DIR" + touch "$LOG_FILE" "$STATUS_FILE" 2>/dev/null || { + print_error "Impossible de créer les fichiers de log" + exit 1 + } + + print_success "Prérequis vérifiés" +} + +print_header() { + clear + + echo -e "${CYAN}" + echo "╔══════════════════════════════════════════════════════════════════╗" + echo "║ SCRIPT DE DURCISSEMENT SYSTÈME OPTIMISÉ v6.0 ║" + echo "║ Sécurité Debian/Ubuntu ║" + echo "╚══════════════════════════════════════════════════════════════════╝" + echo -e "${NC}" + + echo -e "${BLUE}Informations système:${NC}" + echo " • Distribution: $(lsb_release -ds 2>/dev/null || cat /etc/os-release | grep PRETTY_NAME | cut -d'=' -f2 | tr -d '\"')" + echo " • Noyau: $(uname -r)" + echo " • Hostname: $(hostname)" + echo " • Type: $(detect_container && echo "Conteneur/LXC" || echo "Hôte physique/VM")" + echo "" + echo -e "${BLUE}Configuration:${NC}" + echo " • Port SSH nouveau: $NEW_SSH_PORT" + echo " • Fichier log: $LOG_FILE" + echo " • Sauvegardes: $BACKUP_DIR" + echo " • Rapport final: $SECURITY_REPORT" + echo "" + + echo -e "${YELLOW}⚠ Ce script va modifier profondément la configuration système ⚠${NC}" + echo "" + + read -p "Appuyez sur Entrée pour continuer ou Ctrl+C pour annuler..." +} + +print_summary() { + echo -e "\n${GREEN}" + echo "╔══════════════════════════════════════════════════════════════════╗" + echo "║ DURCISSEMENT SYSTÈME TERMINÉ AVEC SUCCÈS ║" + echo "╚══════════════════════════════════════════════════════════════════╝" + echo -e "${NC}" + + # Récupérer le score Lynis + local lynis_score="N/A" + local lynis_max_score=100 + + if [[ -f "/tmp/lynis_score.txt" ]]; then + lynis_score=$(cat /tmp/lynis_score.txt) + [[ -f "/tmp/lynis_max_score.txt" ]] && lynis_max_score=$(cat /tmp/lynis_max_score.txt) + elif [[ -f "$SECURITY_REPORT" ]]; then + lynis_score=$(grep -i "Hardening index" "$SECURITY_REPORT" | grep -oP '\d+' | head -1) + [[ -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 # Barre plus courte pour le résumé + local filled_length=$((percentage * bar_length / 100)) + local empty_length=$((bar_length - filled_length)) + + local bar="[" + for ((i=0; i/dev/null || echo "désactivé (conteneur)")" + echo " • Fail2ban: $(systemctl is-active fail2ban 2>/dev/null || echo "inactif")" + echo " • AIDE: Base initialisée + vérification hebdomadaire" + echo " • ClamAV: $(systemctl is-active clamav-freshclam 2>/dev/null || echo "inactif")" + echo " • Chrony: $(systemctl is-active chrony 2>/dev/null || echo "inactif (conteneur)")" + echo "" + + echo -e "${YELLOW}📁 FICHIERS GÉNÉRÉS:${NC}" + echo " • Log complet: $LOG_FILE" + echo " • Sauvegardes: $BACKUP_DIR" + echo " • Rapport Lynis: $SECURITY_REPORT" + echo " • Rapport chkrootkit: $BACKUP_DIR/chkrootkit_report.log" + 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") + + echo -e "${YELLOW}📈 STATISTIQUES LYNIS:${NC}" + echo " • Avertissements: $warnings" + echo " • Suggestions d'amélioration: $suggestions" + echo "" + fi + + detect_container && { + echo -e "${YELLOW}📦 SPÉCIFICITÉS CONTENEUR:${NC}" + echo " • Process Accounting: Désactivé (géré par hôte)" + echo " • UFW/Pare-feu: Géré par l'hôte Proxmox" + echo " • Modules noyau: Gérés par l'hôte" + echo " • Partitions: Gérées par Proxmox" + echo " • Chrony: Synchronisation horaire gérée par l'hôte" + echo "" + } + + echo -e "${YELLOW}🔍 COMMANDES UTILES POST-INSTALLATION:${NC}" + echo " 1. État Fail2ban: sudo fail2ban-client status sshd" + echo " 2. Logs SSH: sudo tail -f /var/log/auth.log" + echo " 3. Ports ouverts: sudo ss -tlnp" + echo " 4. Règles UFW: sudo ufw status verbose" + echo " 5. Score Lynis: grep 'Hardening index' $SECURITY_REPORT" + echo " 6. Suggestions: grep 'Suggestion' $SECURITY_REPORT" + 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 + echo " ✓ Excellente sécurité ! Votre système est bien durci." + echo " → Continuez à surveiller et à appliquer les mises à jour." + elif [[ $lynis_score -ge 60 ]]; then + echo " ✓ Bonne sécurité, mais des améliorations sont possibles." + echo " → Consultez les suggestions Lynis pour progresser." + elif [[ $lynis_score -ge 40 ]]; then + echo " ⚠ Sécurité moyenne, améliorations recommandées." + echo " → Examinez attentivement les avertissements et suggestions." + else + echo " ⚠ Score faible - plusieurs améliorations nécessaires." + echo " → Priorisez les warnings critiques de Lynis." + fi + echo "" + fi + + echo -e "${RED}══════════════════════════════════════════════════════════════════${NC}" + echo -e "${RED}⚠ TESTEZ SSH:$NEW_SSH_PORT IMMÉDIATEMENT AVANT TOUTE AUTRE ACTION ⚠${NC}" + echo -e "${RED}══════════════════════════════════════════════════════════════════${NC}" + + # Nettoyage + rm -f /tmp/lynis_score.txt /tmp/lynis_max_score.txt 2>/dev/null || true } -list_tasks() { - echo "Tâches disponibles:" - echo " - backup_configs" - echo " - update_system" - echo " - install_tools" - echo " - fail2ban" - echo " - ufw" - echo " - ssh" - echo " - sysctl" - echo " - password_policy" - echo " - limits" - echo " - disable_services" - echo " - clamav" - echo " - aide" - echo " - auto_updates" - echo " - auditd" - echo " - apparmor" - echo " - grub" - echo " - partitions" - echo " - logging" - echo " - security_scan" -} - -reset_all_tasks() { - warn "Réinitialisation de toutes les tâches..." - rm -rf "$STATE_DIR"/*.done "$STATE_DIR"/*.timestamp - success "Toutes les tâches ont été réinitialisées" -} - -# ============================================================================ -# FONCTION PRINCIPALE -# ============================================================================ - main() { - local force_mode=false - local skip_tasks=() - local only_task="" - - # Parser les arguments - while [[ $# -gt 0 ]]; do - case $1 in - -h|--help) - show_help - exit 0 - ;; - -v|--version) - echo "Version $SCRIPT_VERSION" - exit 0 - ;; - -f|--force) - force_mode=true - shift - ;; - -s|--skip) - skip_tasks+=("$2") - shift 2 - ;; - -o|--only) - only_task="$2" - shift 2 - ;; - --status) - show_status - exit 0 - ;; - --reset) - check_root - reset_all_tasks - exit 0 - ;; - --list-tasks) - list_tasks - exit 0 - ;; - *) - error "Option inconnue: $1" - show_help - exit 1 - ;; - esac - done + # Mode nettoyage SSH + [[ $# -eq 1 && "$1" == "--cleanup-ssh" ]] && { + cleanup_ssh_port + return 0 + } # Initialisation - mkdir -p "$STATE_DIR" - touch "$LOG_FILE" + check_requirements + print_header - log "========================================" - log "Script de Durcissement Linux v${SCRIPT_VERSION}" - log "Début: $(date)" - log "========================================" - echo "" + log_message "==================================================" "START" + log_message "Démarrage durcissement système v6.0" "START" + log_message "Système: $(hostname)" "START" + log_message "==================================================" "START" - # Vérifications préliminaires - check_root - check_distribution - check_disk_space - check_internet_connectivity + # EXÉCUTION DES ÉTAPES + install_security_tools + 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_ufw_firewall + 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 - # Acquérir le verrou - acquire_lock + # Résumé + print_summary - # Si mode "only", exécuter uniquement la tâche spécifiée - if [[ -n "$only_task" ]]; then - info "Mode: exécution de la tâche '$only_task' uniquement" - case $only_task in - backup_configs) run_task "backup_configs" backup_configs "$force_mode" ;; - update_system) run_task "update_system" update_system "$force_mode" ;; - install_tools) run_task "install_tools" install_security_tools "$force_mode" ;; - fail2ban) run_task "fail2ban" configure_fail2ban "$force_mode" ;; - ufw) run_task "ufw" configure_ufw "$force_mode" ;; - ssh) run_task "ssh" configure_ssh "$force_mode" ;; - sysctl) run_task "sysctl" configure_sysctl "$force_mode" ;; - password_policy) run_task "password_policy" configure_password_policy "$force_mode" ;; - limits) run_task "limits" configure_limits "$force_mode" ;; - disable_services) run_task "disable_services" disable_unnecessary_services "$force_mode" ;; - clamav) run_task "clamav" configure_clamav "$force_mode" ;; - aide) run_task "aide" configure_aide "$force_mode" ;; - auto_updates) run_task "auto_updates" configure_auto_updates "$force_mode" ;; - auditd) run_task "auditd" configure_auditd "$force_mode" ;; - apparmor) run_task "apparmor" configure_apparmor "$force_mode" ;; - grub) run_task "grub" secure_grub "$force_mode" ;; - partitions) run_task "partitions" secure_partitions "$force_mode" ;; - logging) run_task "logging" configure_logging "$force_mode" ;; - security_scan) run_task "security_scan" run_security_scan "$force_mode" ;; - *) - error "Tâche inconnue: $only_task" - list_tasks - exit 1 - ;; - esac - exit 0 - fi - - # Exécution normale de toutes les tâches - info "Mode: exécution complète (utilisez --only pour exécuter une seule tâche)" - - # Tableau des tâches à exécuter (dans l'ordre) - local task_execution_plan=( - "backup_configs:Sauvegarde des configurations" - "update_system:Mise à jour système" - "install_tools:Installation outils sécurité" - "ssh:Configuration SSH sécurisée" - "ufw:Configuration pare-feu UFW" - "fail2ban:Configuration Fail2ban" - "sysctl:Configuration paramètres kernel" - "password_policy:Politique mots de passe" - "limits:Limites système" - "disable_services:Désactivation services" - "clamav:Configuration antivirus" - "aide:Configuration détection intrusion" - "auto_updates:Mises à jour automatiques" - "auditd:Configuration audit système" - "apparmor:Configuration AppArmor" - "grub:Sécurisation GRUB" - "partitions:Sécurisation partitions" - "logging:Configuration logs" - "security_scan:Scan sécurité final" - ) - - # Exécution des tâches - local total_tasks=${#task_execution_plan[@]} - local current_task=0 - local failed_tasks=() - - for task_entry in "${task_execution_plan[@]}"; do - IFS=':' read -r task_name task_description <<< "$task_entry" - current_task=$((current_task + 1)) - - # Vérifier si la tâche doit être ignorée - if [[ " ${skip_tasks[*]} " == *" $task_name "* ]]; then - info "[$current_task/$total_tasks] Ignoré: $task_description" - continue - fi - - info "[$current_task/$total_tasks] Début: $task_description" - - # Exécuter la tâche - case $task_name in - backup_configs) - run_task "$task_name" backup_configs "$force_mode" || failed_tasks+=("$task_name") - ;; - update_system) - run_task "$task_name" update_system "$force_mode" || failed_tasks+=("$task_name") - ;; - install_tools) - run_task "$task_name" install_security_tools "$force_mode" || failed_tasks+=("$task_name") - ;; - ssh) - run_task "$task_name" configure_ssh "$force_mode" || failed_tasks+=("$task_name") - ;; - ufw) - run_task "$task_name" configure_ufw "$force_mode" || failed_tasks+=("$task_name") - ;; - fail2ban) - run_task "$task_name" configure_fail2ban "$force_mode" || failed_tasks+=("$task_name") - ;; - sysctl) - run_task "$task_name" configure_sysctl "$force_mode" || failed_tasks+=("$task_name") - ;; - password_policy) - run_task "$task_name" configure_password_policy "$force_mode" || failed_tasks+=("$task_name") - ;; - limits) - run_task "$task_name" configure_limits "$force_mode" || failed_tasks+=("$task_name") - ;; - disable_services) - run_task "$task_name" disable_unnecessary_services "$force_mode" || failed_tasks+=("$task_name") - ;; - clamav) - run_task "$task_name" configure_clamav "$force_mode" || failed_tasks+=("$task_name") - ;; - aide) - run_task "$task_name" configure_aide "$force_mode" || failed_tasks+=("$task_name") - ;; - auto_updates) - run_task "$task_name" configure_auto_updates "$force_mode" || failed_tasks+=("$task_name") - ;; - auditd) - run_task "$task_name" configure_auditd "$force_mode" || failed_tasks+=("$task_name") - ;; - apparmor) - run_task "$task_name" configure_apparmor "$force_mode" || failed_tasks+=("$task_name") - ;; - grub) - run_task "$task_name" secure_grub "$force_mode" || failed_tasks+=("$task_name") - ;; - partitions) - run_task "$task_name" secure_partitions "$force_mode" || failed_tasks+=("$task_name") - ;; - logging) - run_task "$task_name" configure_logging "$force_mode" || failed_tasks+=("$task_name") - ;; - security_scan) - run_task "$task_name" run_security_scan "$force_mode" || failed_tasks+=("$task_name") - ;; - esac - - echo "" - done - - # Résumé final - log "========================================" - log "EXÉCUTION TERMINÉE" - log "Date: $(date)" - log "Durée: ~$(($SECONDS / 60)) minutes" - log "========================================" - - if [[ ${#failed_tasks[@]} -eq 0 ]]; then - success "Toutes les tâches ont été exécutées avec succès!" - success "Le système a été durci avec succès." - - # Afficher les recommandations finales - echo "" - info "=== RECOMMANDATIONS FINALES ===" - info "1. Testez votre connexion SSH sur le port ${SSH_PORT}" - info "2. Vérifiez les règles UFW: ufw status verbose" - info "3. Testez Fail2ban: fail2ban-client status" - info "4. Redémarrez le système pour appliquer tous les changements" - info "5. Consultez le rapport de sécurité dans: ${STATE_DIR}/" - - echo "" - warn "IMPORTANT: Sauvegardez vos clés SSH et mots de passe!" - warn "Le redémarrage est recommandé pour appliquer tous les changements." - - else - error "Certaines tâches ont échoué: ${failed_tasks[*]}" - warn "Consultez le fichier de log: $LOG_FILE" - warn "Vous pouvez réessayer les tâches échouées avec: $0 --only " - fi - - echo "" - info "Fichier de log complet: $LOG_FILE" - info "État des tâches: $0 --status" - - # Libérer le verrou - release_lock + log_message "==================================================" "END" + log_message "Durcissement terminé - Durée: $((SECONDS / 60)) min" "END" + log_message "==================================================" "END" } -# ============================================================================ -# POINT D'ENTRÉE DU SCRIPT -# ============================================================================ +# Gestion signaux +trap 'print_error "Script interrompu"; exit 130' INT TERM -# Vérifier que le script n'est pas sourcé -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi - -# ============================================================================ -# NOTES DE SÉCURITÉ FINALES -# ============================================================================ - -# Ce script effectue les actions suivantes: -# 1. Sauvegarde des configurations existantes -# 2. Mise à jour complète du système -# 3. Installation des outils de sécurité essentiels -# 4. Configuration SSH sécurisée (port personnalisé, désactivation root login) -# 5. Configuration du pare-feu UFW avec règles restrictives -# 6. Configuration Fail2ban pour prévention des attaques par force brute -# 7. Hardening des paramètres kernel via sysctl -# 8. Politique de mots de passe stricte -# 9. Limites système pour prévenir les DoS -# 10. Désactivation des services non nécessaires -# 11. Configuration antivirus ClamAV -# 12. Configuration AIDE pour détection d'intrusion -# 13. Mises à jour automatiques de sécurité -# 14. Configuration auditd pour audit système -# 15. Activation d'AppArmor -# 16. Sécurisation du bootloader GRUB -# 17. Recommandations pour sécurisation des partitions -# 18. Configuration avancée des logs -# 19. Scan de sécurité final avec génération de rapport - -# AVERTISSEMENT: -# - Testez toujours dans un environnement de test avant la production -# - Assurez-vous d'avoir un accès de secours (console, KVM, etc.) -# - Conservez une sauvegarde fonctionnelle du système -# - Certaines configurations peuvent nécessiter un redémarrage \ No newline at end of file +# Point d'entrée +[[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@" \ No newline at end of file