system_hardering/system_hardening_optimized.sh

1857 lines
57 KiB
Bash

#!/bin/bash
# Script de durcissement système Linux
# Version: 3.0 - Idempotent et Robuste
# Auteur: Optimisé pour sécurité renforcée et réutilisabilité
set -euo pipefail
# ============================================================================
# CONFIGURATION GLOBALE
# ============================================================================
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"
# Couleurs
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
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"
}
warn() {
local msg="[ATTENTION] $1"
echo -e "${YELLOW}${msg}${NC}"
echo "$msg" >> "$LOG_FILE"
}
error() {
local msg="[ERREUR] $1"
echo -e "${RED}${msg}${NC}" >&2
echo "$msg" >> "$LOG_FILE"
}
info() {
local msg="[INFO] $1"
echo -e "${CYAN}${msg}${NC}"
echo "$msg" >> "$LOG_FILE"
}
success() {
local msg="[OK] $1"
echo -e "${GREEN}${msg}${NC}"
echo "$msg" >> "$LOG_FILE"
}
# 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" ]]
}
# 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"
}
# 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"
}
# Exécuter une tâche de manière idempotente
run_task() {
local task_name="$1"
local task_function="$2"
local force="${3:-false}"
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
else
error "Échec de la tâche '$task_name'"
return 1
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
}
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
fi
error "Ce script est conçu pour les distributions basées sur Debian/Ubuntu"
exit 1
}
check_disk_space() {
local required_space=1048576 # 1GB en KB
local available_space=$(df / | awk 'NR==2 {print $4}')
if [[ $available_space -lt $required_space ]]; then
error "Espace disque insuffisant. Requis: 1GB, Disponible: $((available_space/1024))MB"
exit 1
fi
}
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
}
# ============================================================================
# SAUVEGARDE ET RESTAURATION
# ============================================================================
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" <<EOF
Script Version: $SCRIPT_VERSION
Backup Date: $(date)
Hostname: $(hostname)
Kernel: $(uname -r)
Distribution: $(lsb_release -d | cut -f2)
EOF
log "Sauvegarde créée dans : $backup_dir"
echo "$backup_dir" > "${STATE_DIR}/last_backup_dir"
}
# ============================================================================
# MISE À JOUR ET INSTALLATION
# ============================================================================
update_system() {
log "Mise à jour du système..."
export DEBIAN_FRONTEND=noninteractive
# 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*
# Configurer dpkg pour éviter les prompts
dpkg --configure -a
apt update -qq || {
error "Échec de la mise à jour des dépôts"
return 1
}
apt upgrade -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"
apt autoremove -y -qq
apt autoclean -qq
# Mettre à jour la base de données locate si présente
command -v updatedb &> /dev/null && updatedb || true
}
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é"
fi
done
if [[ ${#failed_packages[@]} -gt 0 ]]; then
warn "Paquets non installés: ${failed_packages[*]}"
fi
}
# ============================================================================
# CONFIGURATION FAIL2BAN
# ============================================================================
configure_fail2ban() {
log "Configuration de Fail2ban..."
# Configuration locale qui ne sera pas écrasée
cat > /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
maxretry = 3
# Action par défaut
banaction = ufw
banaction_allports = ufw
# Email (optionnel)
# destemail = admin@example.com
# sendername = Fail2Ban
# mta = sendmail
[sshd]
enabled = true
port = ${SSH_PORT}
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
EOF
# Ajouter des filtres pour Apache si installé
if systemctl is-active --quiet apache2 2>/dev/null; then
cat >> /etc/fail2ban/jail.local <<EOF
[apache-auth]
enabled = true
logpath = /var/log/apache2/error.log
[apache-badbots]
enabled = true
logpath = /var/log/apache2/access.log
[apache-noscript]
enabled = true
logpath = /var/log/apache2/access.log
[apache-overflows]
enabled = true
logpath = /var/log/apache2/error.log
maxretry = 2
EOF
fi
# Ajouter des filtres pour Nginx si installé
if systemctl is-active --quiet nginx 2>/dev/null; then
cat >> /etc/fail2ban/jail.local <<EOF
[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log
[nginx-noscript]
enabled = true
logpath = /var/log/nginx/access.log
[nginx-badbots]
enabled = true
logpath = /var/log/nginx/access.log
maxretry = 2
[nginx-noproxy]
enabled = true
logpath = /var/log/nginx/access.log
maxretry = 2
EOF
fi
# Ajouter des filtres pour Postfix si installé
if systemctl is-active --quiet postfix 2>/dev/null; then
cat >> /etc/fail2ban/jail.local <<EOF
[postfix-sasl]
enabled = true
logpath = /var/log/mail.log
[postfix-rbl]
enabled = true
logpath = /var/log/mail.log
maxretry = 1
EOF
fi
# Vérifier la configuration
if fail2ban-client -t &> /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
fi
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
# 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 <<EOF
# Configuration SSH durcie - v${SCRIPT_VERSION}
# Généré le $(date)
# Réseau
Port ${SSH_PORT}
AddressFamily inet
ListenAddress 0.0.0.0
# Protocol
Protocol 2
# HostKeys (selon la disponibilité)
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# Logging
SyslogFacility AUTH
LogLevel VERBOSE
# Authentification
LoginGraceTime 30
PermitRootLogin no
StrictModes yes
MaxAuthTries 3
MaxSessions 3
MaxStartups 3:50:10
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
# Désactiver les méthodes d'authentification non sécurisées
HostbasedAuthentication no
IgnoreRhosts yes
PermitEmptyPasswords no
ChallengeResponseAuthentication no
# Authentification par mot de passe (DÉSACTIVÉE pour sécurité)
PasswordAuthentication no
# Kerberos
KerberosAuthentication no
# GSSAPI
GSSAPIAuthentication no
# PAM
UsePAM yes
# Forwarding
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PrintMotd no
PrintLastLog yes
TCPKeepAlive no
PermitTunnel no
GatewayPorts no
# Compression
Compression no
# Client Alive
ClientAliveInterval 300
ClientAliveCountMax 2
# Chiffrement fort
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-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256
# Bannière
Banner /etc/issue.net
# Environnement
PermitUserEnvironment no
AcceptEnv LANG LC_*
# Subsystem
Subsystem sftp /usr/lib/openssh/sftp-server -f AUTHPRIV -l INFO
# Restrictions optionnelles par utilisateur (décommenter et adapter)
# Match User deployer
# PasswordAuthentication yes
# AllowTcpForwarding yes
# Match Group sftp-only
# ChrootDirectory /var/sftp/%u
# ForceCommand internal-sftp
# AllowTcpForwarding no
EOF
# Créer une bannière de sécurité
cat > /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
}
# ============================================================================
# CONFIGURATION SYSCTL (KERNEL)
# ============================================================================
configure_sysctl() {
log "Configuration des paramètres kernel (sysctl)..."
# 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
# ============================================================================
# SÉCURITÉ RÉSEAU IPv4
# ============================================================================
# Protection contre IP spoofing (vérification de la source)
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
# Ignorer les pings ICMP (protection contre ping flood)
net.ipv4.icmp_echo_ignore_all = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# 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
EOF
# Appliquer immédiatement les changements
sysctl -p /etc/sysctl.d/99-hardening.conf
success "Paramètres kernel appliqués"
}
# ============================================================================
# POLITIQUE DE MOTS DE PASSE
# ============================================================================
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
* hard core 0
* soft core 0
# Limites de processus
* soft nproc 65536
* hard nproc 65536
# Limites de 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"
}
# ============================================================================
# DÉSACTIVATION DES MODULES ET SERVICES
# ============================================================================
disable_unnecessary_services() {
log "Désactivation des services et modules non nécessaires..."
# 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
# 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
# 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
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"
fi
fi
done
success "Services inutiles désactivés"
}
# ============================================================================
# CONFIGURATION ANTIVIRUS (CLAMAV)
# ============================================================================
configure_clamav() {
log "Configuration de ClamAV..."
if ! command -v freshclam &> /dev/null; then
warn "ClamAV non installé, passage"
return 0
fi
# Arrêter le service temporairement
systemctl stop clamav-freshclam 2>/dev/null || true
# 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"
if [[ -f /var/lib/aide/aide.db.new ]]; then
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
fi
fi
# 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"
# 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é"
}
# ============================================================================
# MISES À JOUR AUTOMATIQUES
# ============================================================================
configure_auto_updates() {
log "Configuration des mises à jour automatiques de sécurité..."
if ! command -v unattended-upgrade &> /dev/null; then
warn "unattended-upgrades non installé, passage"
return 0
fi
# 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
systemctl enable unattended-upgrades
systemctl restart unattended-upgrades
success "Mises à jour automatiques configurées"
}
# ============================================================================
# CONFIGURATION AUDITD
# ============================================================================
configure_auditd() {
log "Configuration d'auditd (audit système)..."
if ! command -v auditctl &> /dev/null; then
warn "auditd non installé, passage"
return 0
fi
# 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
success "Auditd configuré"
}
# ============================================================================
# CONFIGURATION APPARMOR
# ============================================================================
configure_apparmor() {
log "Configuration d'AppArmor..."
if ! command -v aa-status &> /dev/null; then
warn "AppArmor non installé, passage"
return 0
fi
# Activer AppArmor
systemctl enable apparmor
systemctl start apparmor
# Activer tous les profils en mode enforce
aa-enforce /etc/apparmor.d/* 2>/dev/null || true
# Afficher le statut
aa-status
success "AppArmor configuré"
}
# ============================================================================
# SÉCURISATION DU GRUB
# ============================================================================
secure_grub() {
log "Sécurisation du bootloader GRUB..."
if [[ ! -f /etc/default/grub ]]; then
warn "GRUB non trouvé, passage"
return 0
fi
[[ ! -f /etc/default/grub.bak ]] && cp /etc/default/grub /etc/default/grub.bak
# 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 <VOTRE_HASH>"
fi
# Mettre à jour GRUB
update-grub
success "GRUB sécurisé"
}
# ============================================================================
# SÉCURISATION DES PARTITIONS
# ============================================================================
secure_partitions() {
log "Vérification de la sécurisation des partitions..."
# Créer une copie de fstab
[[ ! -f /etc/fstab.bak ]] && cp /etc/fstab /etc/fstab.bak
# Suggestions pour /tmp, /var/tmp, /dev/shm
info "Vérification des options de montage sécurisées..."
local suggestions=""
# 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
# 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
# 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
# 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
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..."
# Configuration rsyslog pour logs centralisés
cat > /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
# 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..."
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 <<EOF
Script de Durcissement Linux v${SCRIPT_VERSION}
Usage: $0 [OPTIONS]
OPTIONS:
-h, --help Afficher cette aide
-v, --version Afficher la version
-f, --force Forcer la réexécution de toutes les tâches
-s, --skip TASK Ignorer une tâche spécifique
-o, --only TASK Exécuter uniquement une tâche spécifique
--status Afficher l'état des tâches
--reset Réinitialiser toutes les tâches
--list-tasks Lister toutes les tâches disponibles
EXEMPLES:
$0 # Exécution normale
$0 --force # Réexécuter toutes les tâches
$0 --only update # Exécuter uniquement la mise à jour
$0 --skip clamav # Ignorer la configuration ClamAV
$0 --status # Voir quelles tâches sont terminées
TÂCHES DISPONIBLES:
- backup_configs Sauvegarde des configurations
- update_system Mise à jour du système
- install_tools Installation des outils de sécurité
- fail2ban Configuration Fail2ban
- ufw Configuration pare-feu UFW
- ssh Configuration SSH sécurisée
- sysctl Configuration paramètres kernel
- password_policy Politique de mots de passe
- limits Limites système
- disable_services Désactivation services inutiles
- 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 de sécurité final
EOF
}
show_status() {
log "État des tâches de durcissement:"
echo ""
local tasks=(
"backup_configs"
"update_system"
"install_tools"
"fail2ban"
"ufw"
"ssh"
"sysctl"
"password_policy"
"limits"
"disable_services"
"clamav"
"aide"
"auto_updates"
"auditd"
"apparmor"
"grub"
"partitions"
"logging"
"security_scan"
)
for task in "${tasks[@]}"; do
if is_task_done "$task"; then
local timestamp=$(cat "${STATE_DIR}/${task}.timestamp" 2>/dev/null || echo "inconnue")
echo -e "${GREEN}[✓]${NC} $task (${timestamp})"
else
echo -e "${RED}[✗]${NC} $task"
fi
done
}
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
# Initialisation
mkdir -p "$STATE_DIR"
touch "$LOG_FILE"
log "========================================"
log "Script de Durcissement Linux v${SCRIPT_VERSION}"
log "Début: $(date)"
log "========================================"
echo ""
# Vérifications préliminaires
check_root
check_distribution
check_disk_space
check_internet_connectivity
# Acquérir le verrou
acquire_lock
# 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 <task_name>"
fi
echo ""
info "Fichier de log complet: $LOG_FILE"
info "État des tâches: $0 --status"
# Libérer le verrou
release_lock
}
# ============================================================================
# POINT D'ENTRÉE DU SCRIPT
# ============================================================================
# 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