Actualiser system_hardening_optimized.sh
This commit is contained in:
parent
844395e911
commit
171957aca5
|
|
@ -45,6 +45,7 @@ readonly DEFAULT_UMASK="027"
|
|||
: "${AUTO_YES:=no}"
|
||||
: "${AUTO_CLEANUP_SSH:=no}"
|
||||
: "${AUTO_CHANGE_ROOT_PWD:=yes}"
|
||||
: "${AUTO_SKIP_DEBSUMS_CONTAINER:=yes}"
|
||||
|
||||
TOTAL_STEPS=33
|
||||
CURRENT_STEP=1
|
||||
|
|
@ -198,12 +199,141 @@ skip_step() {
|
|||
}
|
||||
|
||||
detect_container() {
|
||||
grep -qE "lxc|container" /proc/self/cgroup 2>/dev/null || \
|
||||
[[ -f /.dockerenv ]] || [[ -d /dev/lxc ]]
|
||||
# -----------------------------------------------------------------
|
||||
# DÉTECTION DE TOUS TYPES DE CONTENEURS (LXC, Docker, systemd-nspawn, etc.)
|
||||
# Retourne 0 si dans un conteneur, 1 sinon
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# 1. FICHIERS SPÉCIFIQUES
|
||||
[[ -f /.dockerenv ]] && { log_message "Conteneur détecté: /.dockerenv" "DETECT"; return 0; }
|
||||
[[ -d /dev/lxc ]] && { log_message "Conteneur détecté: /dev/lxc" "DETECT"; return 0; }
|
||||
[[ -f /.lxcpid ]] && { log_message "Conteneur détecté: /.lxcpid" "DETECT"; return 0; }
|
||||
|
||||
# 2. VARIABLES D'ENVIRONNEMENT (utilisation de ${var:-} pour éviter "unbound variable")
|
||||
[[ -n "${container:-}" ]] && { log_message "Conteneur détecté: variable \$container=$container" "DETECT"; return 0; }
|
||||
[[ -n "${DOCKER_HOST:-}" ]] && { log_message "Conteneur détecté: variable \$DOCKER_HOST" "DETECT"; return 0; }
|
||||
[[ -n "${KUBERNETES_SERVICE_HOST:-}" ]] && { log_message "Conteneur détecté: Kubernetes" "DETECT"; return 0; }
|
||||
|
||||
# 3. CGROUPS (compatible v1 et v2)
|
||||
if [[ -f /proc/1/cgroup ]]; then
|
||||
# Lecture de /proc/1/cgroup (plus fiable que /proc/self/cgroup)
|
||||
local cgroup_content
|
||||
cgroup_content=$(cat /proc/1/cgroup 2>/dev/null || echo "")
|
||||
|
||||
# Modèles de conteneurs dans cgroups
|
||||
if echo "$cgroup_content" | grep -qE "(docker|lxc|kubepods|containerd|podman|buildkit|systemd-nspawn|libpod)"; then
|
||||
log_message "Conteneur détecté: cgroups pattern" "DETECT"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Cgroups v2: format "0::/"
|
||||
if echo "$cgroup_content" | grep -q "^0::/"; then
|
||||
# Vérifier si le chemin n'est pas un chemin système standard
|
||||
local cgroup_path
|
||||
cgroup_path=$(echo "$cgroup_content" | grep "^0::/" | cut -d: -f3)
|
||||
|
||||
# Les chemins typiques des conteneurs
|
||||
if [[ "$cgroup_path" == "/" ]] ||
|
||||
[[ "$cgroup_path" == /user.slice* ]] ||
|
||||
[[ "$cgroup_path" == /system.slice* ]]; then
|
||||
# Pour cgroups v2, vérifier l'isolation des namespaces
|
||||
if [[ -r /proc/1/ns/pid ]] && [[ -r /proc/self/ns/pid ]]; then
|
||||
local pid1_inode
|
||||
local self_inode
|
||||
pid1_inode=$(stat -Lc '%i' /proc/1/ns/pid 2>/dev/null)
|
||||
self_inode=$(stat -Lc '%i' /proc/self/ns/pid 2>/dev/null)
|
||||
|
||||
# Si les inodes sont différents, on est dans un namespace PID isolé (conteneur)
|
||||
if [[ -n "$pid1_inode" ]] && [[ -n "$self_inode" ]] && [[ "$pid1_inode" != "$self_inode" ]]; then
|
||||
log_message "Conteneur détecté: namespace PID isolé (cgroups v2)" "DETECT"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Chemin non standard -> probablement un conteneur
|
||||
log_message "Conteneur détecté: cgroups v2 path non standard: $cgroup_path" "DETECT"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4. SYSTEMD-DETECT-VIRT (outil natif)
|
||||
if command -v systemd-detect-virt >/dev/null 2>&1; then
|
||||
local virt
|
||||
virt=$(systemd-detect-virt 2>/dev/null)
|
||||
case "$virt" in
|
||||
"container"|"lxc"|"lxc-libvirt"|"systemd-nspawn"|"docker"|"podman"|"wsl")
|
||||
log_message "Conteneur détecté: systemd-detect-virt=$virt" "DETECT"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 5. VÉRIFICATION DES PROCESSUS ET NAMESPACES
|
||||
# Vérifier l'isolation des namespaces (méthode avancée)
|
||||
if [[ -r /proc/1/ns/pid ]] && [[ -r /proc/self/ns/pid ]]; then
|
||||
local ns_pid1
|
||||
local ns_self
|
||||
ns_pid1=$(readlink /proc/1/ns/pid 2>/dev/null)
|
||||
ns_self=$(readlink /proc/self/ns/pid 2>/dev/null)
|
||||
|
||||
if [[ -n "$ns_pid1" ]] && [[ -n "$ns_self" ]] && [[ "$ns_pid1" != "$ns_self" ]]; then
|
||||
log_message "Conteneur détecté: namespace PID différent (PID1: $ns_pid1, Self: $ns_self)" "DETECT"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 6. VÉRIFICATION DES PROCESSUS DE GESTION DE CONTENEURS
|
||||
if ps -eo comm 2>/dev/null | grep -qE "^(containerd|dockerd|runc|crun|podman|CRIO)$"; then
|
||||
# Si un gestionnaire de conteneurs tourne, vérifier si nous sommes dans un conteneur
|
||||
if [[ "$(unshare --pid --fork --mount-proc readlink /proc/1/exe 2>/dev/null)" != "/sbin/init" ]]; then
|
||||
log_message "Conteneur détecté: gestionnaire de conteneurs actif" "DETECT"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 7. VÉRIFICATION DE L'INIT (PID 1)
|
||||
local init_cmd
|
||||
init_cmd=$(ps -p 1 -o comm= 2>/dev/null || cat /proc/1/comm 2>/dev/null)
|
||||
case "$init_cmd" in
|
||||
"systemd"|"init"|"upstart")
|
||||
# Init système normal - probablement pas un conteneur
|
||||
;;
|
||||
"containerd-shim"|"runc"|"docker-init"|"tini")
|
||||
log_message "Conteneur détecté: init spécial: $init_cmd" "DETECT"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# 8. FICHIERS SPÉCIFIQUES À CERTAINS CONTENEURS
|
||||
[[ -f /run/.containerenv ]] && { log_message "Conteneur détecté: /run/.containerenv" "DETECT"; return 0; }
|
||||
[[ -d /run/host ]] && {
|
||||
# /run/host existe souvent dans les conteneurs systemd-nspawn
|
||||
if ! mountpoint -q /run/host 2>/dev/null; then
|
||||
log_message "Conteneur détecté: /run/host présent" "DETECT"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 9. VOLUMES DOCKER SPÉCIFIQUES (optionnel)
|
||||
if [[ -d /var/lib/docker ]] && mountpoint -q /var/lib/docker 2>/dev/null; then
|
||||
# /var/lib/docker est monté - pourrait être un daemon Docker
|
||||
log_message "Docker détecté via /var/lib/docker monté" "DETECT"
|
||||
# Note: Ceci détecte le daemon Docker, pas forcément qu'on est dans un conteneur
|
||||
fi
|
||||
|
||||
# Aucune détection positive
|
||||
log_message "Aucun conteneur détecté" "DETECT"
|
||||
return 1
|
||||
}
|
||||
|
||||
detect_lxc() {
|
||||
grep -q "lxc" /proc/self/cgroup 2>/dev/null || [[ -d /dev/lxc ]]
|
||||
# Détection spécifique LXC
|
||||
[[ -d /dev/lxc ]] && return 0
|
||||
[[ -f /.lxcpid ]] && return 0
|
||||
grep -q "lxc" /proc/1/cgroup 2>/dev/null && return 0
|
||||
[[ "$(systemd-detect-virt 2>/dev/null)" == "lxc" ]] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
backup_file() {
|
||||
|
|
@ -649,6 +779,88 @@ get_ssh_port_to_use() {
|
|||
# FONCTIONS DE DURCISSEMENT (COMPLÈTES)
|
||||
# ==============================================================================
|
||||
|
||||
configure_banners() {
|
||||
local step_name="configure_banners"
|
||||
if check_step_done "$step_name"; then
|
||||
skip_step "${STEP_DESCRIPTIONS[$step_name]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_step "Configuration des bannières légales"
|
||||
|
||||
# Bannière pour les connexions locales (login)
|
||||
local issue_banner="
|
||||
╔══════════════════════════════════════════════════════════════════╗
|
||||
║ SYSTÈME SÉCURISÉ ║
|
||||
║ ║
|
||||
║ Accès strictement réservé aux personnes autorisées. ║
|
||||
║ Toute tentative d'accès non autorisé est strictement interdite ║
|
||||
║ et fera l'objet de poursuites judiciaires. ║
|
||||
║ ║
|
||||
║ Toutes les activités sur ce système sont surveillées et ║
|
||||
║ enregistrées conformément à la réglementation en vigueur. ║
|
||||
║ ║
|
||||
║ Date et heure: \$(date) ║
|
||||
║ Système: \$(hostname) (\$(uname -o) \$(uname -r)) ║
|
||||
╚══════════════════════════════════════════════════════════════════╝
|
||||
"
|
||||
|
||||
# Bannière pour SSH (issue.net)
|
||||
local issue_net_banner="
|
||||
╔══════════════════════════════════════════════════════════════════╗
|
||||
║ SYSTÈME SÉCURISÉ ║
|
||||
║ ║
|
||||
║ ATTENTION: Accès restreint aux utilisateurs autorisés ║
|
||||
║ ║
|
||||
║ Vous accédez à un système informatique protégé. ║
|
||||
║ Toute utilisation non autorisée est interdite et ║
|
||||
║ peut faire l'objet de poursuites. ║
|
||||
║ ║
|
||||
║ En vous connectant, vous acceptez que votre session ║
|
||||
║ soit surveillée et enregistrée. ║
|
||||
║ ║
|
||||
║ Système: \$(hostname) ║
|
||||
║ Adresse IP: \$(who am i | awk '{print \$5}' | sed 's/[()]//g') ║
|
||||
╚══════════════════════════════════════════════════════════════════╝
|
||||
"
|
||||
|
||||
# Bannière pour motd (Message of the Day)
|
||||
local motd_banner="
|
||||
========================================================================
|
||||
SYSTÈME SÉCURISÉ
|
||||
------------------------------------------------------------------------
|
||||
Ce système est configuré pour une haute sécurité.
|
||||
Toutes les connexions sont tracées et enregistrées.
|
||||
|
||||
Dernière mise à jour sécurité: $(date +%Y-%m-%d)
|
||||
Connexions actives: $(who | wc -l)
|
||||
Uptime: $(uptime -p)
|
||||
========================================================================
|
||||
"
|
||||
|
||||
# Appliquer les bannières
|
||||
print_info "Configuration de /etc/issue (login local)..."
|
||||
echo "$issue_banner" > /etc/issue
|
||||
chmod 644 /etc/issue
|
||||
|
||||
print_info "Configuration de /etc/issue.net (SSH)..."
|
||||
echo "$issue_net_banner" > /etc/issue.net
|
||||
chmod 644 /etc/issue.net
|
||||
|
||||
print_info "Configuration de /etc/motd (Message du jour)..."
|
||||
echo "$motd_banner" > /etc/motd
|
||||
chmod 644 /etc/motd
|
||||
|
||||
# Désactiver les motd dynamiques si existants
|
||||
if [[ -d /etc/update-motd.d ]]; then
|
||||
print_info "Désactivation des motd dynamiques..."
|
||||
chmod -x /etc/update-motd.d/* 2>/dev/null || true
|
||||
fi
|
||||
|
||||
print_success "Bannières légales configurées"
|
||||
mark_step_done "$step_name"
|
||||
}
|
||||
|
||||
install_security_tools() {
|
||||
local step_name="install_security_tools"
|
||||
if check_step_done "$step_name"; then
|
||||
|
|
@ -1401,72 +1613,148 @@ harden_ssh() {
|
|||
backup_file "/etc/ssh/sshd_config"
|
||||
|
||||
local sshd_config="/etc/ssh/sshd_config"
|
||||
local ssh_port=$(get_ssh_port_to_use)
|
||||
|
||||
# Fonction utilitaire pour mettre à jour les paramètres SSH
|
||||
update_ssh_param() {
|
||||
local param="$1"
|
||||
local value="$2"
|
||||
sed -i "/^#*${param}[[:space:]]/d" "$sshd_config"
|
||||
echo "$param $value" >> "$sshd_config"
|
||||
}
|
||||
|
||||
# Configuration de base
|
||||
update_ssh_param "Port" "$ssh_port"
|
||||
|
||||
# Si c'est un nouveau port et pas en LXC, garder le port 22 temporairement
|
||||
if [[ "$ssh_port" != "22" ]] && ! detect_lxc; then
|
||||
update_ssh_param "Port" "22"
|
||||
update_ssh_param "Port" "$ssh_port"
|
||||
print_info "Port 22 maintenu temporairement avec port $ssh_port"
|
||||
fi
|
||||
|
||||
# Authentification
|
||||
if [[ "$AUTO_DISABLE_ROOT_LOGIN" == "yes" ]]; then
|
||||
update_ssh_param "PermitRootLogin" "no"
|
||||
print_info "Connexion root SSH désactivée"
|
||||
# DÉTERMINER LE PORT SSH À UTILISER
|
||||
local ssh_port="22" # Par défaut
|
||||
if detect_lxc; then
|
||||
print_info "Conteneur LXC détecté - utilisation du port 22"
|
||||
ssh_port="22"
|
||||
else
|
||||
update_ssh_param "PermitRootLogin" "prohibit-password"
|
||||
print_info "Connexion root SSH autorisée uniquement par clé"
|
||||
ssh_port="$AUTO_SSH_PORT"
|
||||
# Valider que le port est un nombre entre 1 et 65535
|
||||
if ! [[ "$ssh_port" =~ ^[0-9]+$ ]] || [ "$ssh_port" -lt 1 ] || [ "$ssh_port" -gt 65535 ]; then
|
||||
print_warning "Port SSH invalide ($ssh_port) - utilisation du port 22"
|
||||
ssh_port="22"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Paramètres de sécurité
|
||||
update_ssh_param "PasswordAuthentication" "no"
|
||||
update_ssh_param "PubkeyAuthentication" "yes"
|
||||
update_ssh_param "PermitEmptyPasswords" "no"
|
||||
update_ssh_param "X11Forwarding" "no"
|
||||
update_ssh_param "MaxAuthTries" "3"
|
||||
update_ssh_param "ClientAliveInterval" "300"
|
||||
update_ssh_param "ClientAliveCountMax" "2"
|
||||
update_ssh_param "LoginGraceTime" "60"
|
||||
update_ssh_param "MaxSessions" "2"
|
||||
update_ssh_param "TCPKeepAlive" "no"
|
||||
update_ssh_param "AllowAgentForwarding" "no"
|
||||
update_ssh_param "AllowTcpForwarding" "no"
|
||||
update_ssh_param "LogLevel" "VERBOSE"
|
||||
update_ssh_param "Compression" "no"
|
||||
update_ssh_param "Protocol" "2"
|
||||
update_ssh_param "UseDNS" "no"
|
||||
update_ssh_param "IgnoreRhosts" "yes"
|
||||
update_ssh_param "HostbasedAuthentication" "no"
|
||||
update_ssh_param "PrintLastLog" "yes"
|
||||
update_ssh_param "StrictModes" "yes"
|
||||
print_info "Configuration SSH avec le port: $ssh_port"
|
||||
|
||||
# Algorithmes modernes
|
||||
cat >> "$sshd_config" << 'EOF'
|
||||
# Algorithmes de chiffrement modernes
|
||||
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,umac-128-etm@openssh.com
|
||||
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
|
||||
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com
|
||||
# CRÉER UNE CONFIGURATION SSH SÉCURISÉE
|
||||
# D'abord créer un fichier temporaire
|
||||
local temp_config=$(mktemp)
|
||||
|
||||
# Construire la configuration ligne par ligne pour éviter les problèmes de formatage
|
||||
{
|
||||
echo "# ============================================================================"
|
||||
echo "# Configuration SSH sécurisée - Générée automatiquement $(date)"
|
||||
echo "# ============================================================================"
|
||||
echo ""
|
||||
|
||||
# Section Ports
|
||||
echo "# Ports d'écoute"
|
||||
if [[ "$ssh_port" != "22" ]] && ! detect_lxc; then
|
||||
echo "Port 22"
|
||||
echo "Port $ssh_port"
|
||||
echo "# Port 22 maintenu temporairement pour la transition"
|
||||
else
|
||||
echo "Port $ssh_port"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "# Adresse d'écoute"
|
||||
echo "ListenAddress 0.0.0.0"
|
||||
echo "ListenAddress ::"
|
||||
echo ""
|
||||
|
||||
echo "# Authentification"
|
||||
if [[ "$AUTO_DISABLE_ROOT_LOGIN" == "yes" ]]; then
|
||||
echo "PermitRootLogin no"
|
||||
print_info "Connexion root SSH désactivée"
|
||||
else
|
||||
echo "PermitRootLogin prohibit-password"
|
||||
print_info "Connexion root SSH autorisée uniquement par clé"
|
||||
fi
|
||||
echo "PasswordAuthentication no"
|
||||
echo "PubkeyAuthentication yes"
|
||||
echo "PermitEmptyPasswords no"
|
||||
echo "MaxAuthTries 3"
|
||||
echo "LoginGraceTime 60"
|
||||
echo "ClientAliveInterval 300"
|
||||
echo "ClientAliveCountMax 2"
|
||||
echo "MaxSessions 2"
|
||||
echo ""
|
||||
|
||||
echo "# Sécurité"
|
||||
echo "Protocol 2"
|
||||
echo "StrictModes yes"
|
||||
echo "UseDNS no"
|
||||
echo "IgnoreRhosts yes"
|
||||
echo "HostbasedAuthentication no"
|
||||
echo "PrintLastLog yes"
|
||||
echo ""
|
||||
|
||||
echo "# Redirections"
|
||||
echo "X11Forwarding no"
|
||||
echo "AllowAgentForwarding no"
|
||||
echo "AllowTcpForwarding no"
|
||||
echo "TCPKeepAlive no"
|
||||
echo ""
|
||||
|
||||
echo "# Performances et logs"
|
||||
echo "Compression no"
|
||||
echo "LogLevel VERBOSE"
|
||||
echo ""
|
||||
|
||||
echo "# Bannière"
|
||||
echo "Banner /etc/issue.net"
|
||||
echo ""
|
||||
|
||||
echo "# Algorithmes de chiffrement modernes"
|
||||
echo "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
|
||||
echo "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com"
|
||||
echo "KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256"
|
||||
echo "HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com"
|
||||
echo ""
|
||||
echo "# ============================================================================"
|
||||
} > "$temp_config"
|
||||
|
||||
# VÉRIFIER LE FICHIER TEMPORAIRE
|
||||
print_info "Vérification du fichier temporaire..."
|
||||
if ! sshd -t -f "$temp_config" 2>&1; then
|
||||
print_error "Configuration temporaire invalide - affichage du contenu :"
|
||||
cat -n "$temp_config"
|
||||
print_info "Tentative avec configuration minimaliste..."
|
||||
|
||||
# Configuration minimaliste pour LXC
|
||||
cat > "$temp_config" << EOF
|
||||
Port 22
|
||||
Protocol 2
|
||||
PermitRootLogin prohibit-password
|
||||
PasswordAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
X11Forwarding no
|
||||
AllowTcpForwarding no
|
||||
AllowAgentForwarding no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
PrintLastLog yes
|
||||
TCPKeepAlive no
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
EOF
|
||||
|
||||
if ! sshd -t -f "$temp_config" 2>&1; then
|
||||
print_error "Configuration minimaliste aussi invalide"
|
||||
rm -f "$temp_config"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Bannière
|
||||
update_ssh_param "Banner" "/etc/issue.net"
|
||||
# COPIER LA CONFIGURATION
|
||||
cp "$temp_config" "$sshd_config"
|
||||
chmod 600 "$sshd_config"
|
||||
chown root:root "$sshd_config"
|
||||
rm -f "$temp_config"
|
||||
|
||||
# Test et application
|
||||
print_info "Test de la configuration SSH..."
|
||||
if sshd -t 2>&1 | tee -a "$LOG_FILE"; then
|
||||
# AFFICHER LES PREMIÈRES LIGNES POUR VÉRIFICATION
|
||||
print_info "Premières lignes de la configuration :"
|
||||
head -n 15 "$sshd_config" | cat -n
|
||||
|
||||
# TEST FINAL ET APPLICATION
|
||||
print_info "Test final de la configuration SSH..."
|
||||
if sshd -t -f "$sshd_config" 2>&1 | tee -a "$LOG_FILE"; then
|
||||
print_success "Configuration SSH valide"
|
||||
|
||||
print_info "Redémarrage du service SSH..."
|
||||
|
|
@ -1476,12 +1764,10 @@ EOF
|
|||
if [[ "$ssh_port" != "22" ]] && ! detect_lxc; then
|
||||
print_warning "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
print_warning "⚠ Port SSH: $ssh_port (22 temporairement actif)"
|
||||
if [[ "$AUTO_CLEANUP_SSH" == "yes" ]] || auto_confirm; then
|
||||
print_info "Nettoyage automatique du port 22 programmé"
|
||||
else
|
||||
print_warning "Testez: ssh -p $ssh_port $(whoami)@$(hostname -I | awk '{print $1}')"
|
||||
fi
|
||||
print_warning "Testez: ssh -p $ssh_port $(whoami)@localhost"
|
||||
print_warning "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
else
|
||||
print_info "Port SSH: $ssh_port"
|
||||
fi
|
||||
else
|
||||
print_error "Échec redémarrage SSH - restauration..."
|
||||
|
|
@ -1490,7 +1776,9 @@ EOF
|
|||
return 1
|
||||
fi
|
||||
else
|
||||
print_error "Configuration SSH invalide"
|
||||
print_error "Configuration SSH invalide après copie"
|
||||
print_info "Contenu complet du fichier :"
|
||||
cat -n "$sshd_config"
|
||||
cp "${BACKUP_DIR}/sshd_config" /etc/ssh/sshd_config
|
||||
return 1
|
||||
fi
|
||||
|
|
@ -1498,31 +1786,6 @@ EOF
|
|||
mark_step_done "$step_name"
|
||||
}
|
||||
|
||||
configure_banners() {
|
||||
local step_name="configure_banners"
|
||||
if check_step_done "$step_name"; then
|
||||
skip_step "${STEP_DESCRIPTIONS[$step_name]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
configure_firewall_ports() {
|
||||
local step_name="configure_firewall_ports"
|
||||
if check_step_done "$step_name"; then
|
||||
|
|
@ -1840,51 +2103,131 @@ verify_packages_integrity() {
|
|||
print_step "Vérification de l'intégrité des paquets"
|
||||
|
||||
print_info "Vérification avec debsums..."
|
||||
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"
|
||||
}
|
||||
|
||||
configure_automatic_updates() {
|
||||
local step_name="configure_automatic_updates"
|
||||
if check_step_done "$step_name"; then
|
||||
skip_step "${STEP_DESCRIPTIONS[$step_name]}"
|
||||
# Vérifier si debsums est installé
|
||||
if ! command -v debsums > /dev/null 2>&1; then
|
||||
print_warning "debsums n'est pas installé - installation..."
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq debsums 2>/dev/null || {
|
||||
print_error "Impossible d'installer debsums"
|
||||
mark_step_done "$step_name"
|
||||
return 0
|
||||
}
|
||||
fi
|
||||
|
||||
# Vérifier si debsums peut s'exécuter
|
||||
if ! debsums --help > /dev/null 2>&1; then
|
||||
print_warning "debsums ne fonctionne pas correctement"
|
||||
mark_step_done "$step_name"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_step "Configuration des mises à jour automatiques"
|
||||
if detect_container; then
|
||||
print_info "Conteneur détecté - filtrage des faux positifs courants..."
|
||||
|
||||
# Liste des fichiers communément modifiés dans les conteneurs (faux positifs)
|
||||
local ignore_patterns=(
|
||||
"/lib/systemd/system/container-getty@.service"
|
||||
"/etc/hosts"
|
||||
"/etc/resolv.conf"
|
||||
"/etc/hostname"
|
||||
"/etc/mtab"
|
||||
"/etc/localtime"
|
||||
"/etc/timezone"
|
||||
"/etc/machine-id"
|
||||
"/var/lib/dbus/machine-id"
|
||||
)
|
||||
|
||||
# Construire l'expression grep pour ignorer ces fichiers
|
||||
local grep_pattern=$(printf "|%s" "${ignore_patterns[@]}")
|
||||
grep_pattern=${grep_pattern:1} # Enlever le premier |
|
||||
|
||||
# Exécuter debsums en filtrant les faux positifs
|
||||
local debsums_output
|
||||
debsums_output=$(debsums -s 2>&1 || true)
|
||||
|
||||
if [[ -n "$debsums_output" ]]; then
|
||||
# Filtrer les faux positifs et les erreurs de permission
|
||||
local filtered_output
|
||||
filtered_output=$(echo "$debsums_output" | grep -vE "$grep_pattern" | grep -v "Permission denied" || true)
|
||||
|
||||
if [[ -n "$filtered_output" ]]; then
|
||||
echo "$filtered_output" | tee -a "$LOG_FILE"
|
||||
|
||||
# Compter les vraies erreurs
|
||||
local real_errors
|
||||
real_errors=$(echo "$filtered_output" | wc -l)
|
||||
|
||||
if [[ $real_errors -gt 0 ]]; then
|
||||
print_warning "$real_errors paquet(s) avec des erreurs réelles"
|
||||
|
||||
# Lister les paquets problématiques
|
||||
echo ""
|
||||
echo "Paquets concernés:"
|
||||
echo "$filtered_output" | awk -F: '{print $1}' | sort -u
|
||||
|
||||
# Proposer une réparation en mode interactif
|
||||
if ! auto_confirm; then
|
||||
echo ""
|
||||
read -p "Voulez-vous tenter de réparer les paquets corrompus ? (o/N): " -r repair
|
||||
if [[ "$repair" =~ ^[Oo]$ ]]; then
|
||||
print_info "Réparation des paquets..."
|
||||
local packages_to_reinstall
|
||||
packages_to_reinstall=$(echo "$filtered_output" | awk -F: '{print $1}' | sort -u | tr '\n' ' ')
|
||||
if [[ -n "$packages_to_reinstall" ]]; then
|
||||
apt-get install --reinstall -y $packages_to_reinstall 2>&1 | tee -a "$LOG_FILE" || \
|
||||
print_warning "Certains paquets n'ont pas pu être réinstallés"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
print_success "Aucune erreur réelle détectée (faux positifs filtrés)"
|
||||
fi
|
||||
else
|
||||
print_success "Aucune modification détectée (après filtrage)"
|
||||
fi
|
||||
else
|
||||
print_success "Aucune modification détectée"
|
||||
fi
|
||||
else
|
||||
# Système hôte - vérification complète
|
||||
local debsums_output
|
||||
debsums_output=$(debsums -s 2>&1 || true)
|
||||
|
||||
# Filtrer les erreurs de permission
|
||||
local filtered_output
|
||||
filtered_output=$(echo "$debsums_output" | grep -v "Permission denied" || true)
|
||||
|
||||
if [[ -n "$filtered_output" ]]; then
|
||||
echo "$filtered_output" | tee -a "$LOG_FILE"
|
||||
|
||||
print_warning "Certains paquets ont des erreurs"
|
||||
|
||||
# Lister les paquets problématiques
|
||||
echo ""
|
||||
echo "Paquets concernés:"
|
||||
echo "$filtered_output" | awk -F: '{print $1}' | sort -u
|
||||
|
||||
# Proposer une réparation
|
||||
if ! auto_confirm; then
|
||||
echo ""
|
||||
read -p "Voulez-vous tenter de réparer ces paquets ? (o/N): " -r repair
|
||||
if [[ "$repair" =~ ^[Oo]$ ]]; then
|
||||
print_info "Réparation des paquets..."
|
||||
local packages_to_reinstall
|
||||
packages_to_reinstall=$(echo "$filtered_output" | awk -F: '{print $1}' | sort -u | tr '\n' ' ')
|
||||
if [[ -n "$packages_to_reinstall" ]]; then
|
||||
apt-get install --reinstall -y $packages_to_reinstall 2>&1 | tee -a "$LOG_FILE" || \
|
||||
print_warning "Certains paquets n'ont pas pu être réinstallés"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
print_success "Tous les paquets sont intacts"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Configuration unattended-upgrades
|
||||
cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
|
||||
Unattended-Upgrade::Allowed-Origins {
|
||||
"${distro_id}:${distro_codename}";
|
||||
"${distro_id}:${distro_codename}-security";
|
||||
"${distro_id}ESM:${distro_codename}";
|
||||
};
|
||||
Unattended-Upgrade::Origins-Pattern {
|
||||
"origin=Debian,codename=${distro_codename},label=Debian-Security";
|
||||
};
|
||||
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";
|
||||
EOF
|
||||
|
||||
# Configuration périodique
|
||||
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"
|
||||
}
|
||||
|
||||
configure_aide_cron() {
|
||||
local step_name="configure_aide_cron"
|
||||
if check_step_done "$step_name"; then
|
||||
|
|
@ -2281,6 +2624,175 @@ cleanup_ssh_port() {
|
|||
fi
|
||||
}
|
||||
|
||||
configure_automatic_updates() {
|
||||
local step_name="configure_automatic_updates"
|
||||
if check_step_done "$step_name"; then
|
||||
skip_step "${STEP_DESCRIPTIONS[$step_name]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_step "Configuration des mises à jour automatiques"
|
||||
|
||||
# Vérifier si unattended-upgrades est installé
|
||||
if ! dpkg -l | grep -q "^ii.*unattended-upgrades"; then
|
||||
print_info "Installation de unattended-upgrades..."
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq unattended-upgrades apt-listchanges needrestart 2>/dev/null || {
|
||||
print_warning "Échec installation complète - continuation avec ce qui est disponible"
|
||||
}
|
||||
fi
|
||||
|
||||
# Configuration principale de unattended-upgrades
|
||||
backup_file "/etc/apt/apt.conf.d/50unattended-upgrades"
|
||||
|
||||
cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
|
||||
// Configuration des mises à jour automatiques sécurisées
|
||||
Unattended-Upgrade::Allowed-Origins {
|
||||
"${distro_id}:${distro_codename}";
|
||||
"${distro_id}:${distro_codename}-security";
|
||||
"${distro_id}:${distro_codename}-updates";
|
||||
"${distro_id}ESM:${distro_codename}";
|
||||
"${distro_id}ESM-Apps:${distro_codename}";
|
||||
};
|
||||
|
||||
// Options de comportement
|
||||
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
||||
Unattended-Upgrade::MinimalSteps "true";
|
||||
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
|
||||
Unattended-Upgrade::Automatic-Reboot "false";
|
||||
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
|
||||
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
|
||||
|
||||
// Nettoyage automatique
|
||||
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
|
||||
// Notifications par email (si postfix/sendmail est installé)
|
||||
Unattended-Upgrade::Mail "root";
|
||||
Unattended-Upgrade::MailOnlyOnError "true";
|
||||
Unattended-Upgrade::MailReport "on-change";
|
||||
|
||||
// Téléchargement et installation
|
||||
Unattended-Upgrade::Download-Upgradeable-Packages "true";
|
||||
Unattended-Upgrade::DevRelease "auto";
|
||||
|
||||
// Mise à jour du GRUB si nécessaire
|
||||
Unattended-Upgrade::Update-Boot-App "true";
|
||||
EOF
|
||||
|
||||
# Configuration périodique pour APT (ne pas essayer de sauvegarder si le fichier n'existe pas)
|
||||
if [[ -f "/etc/apt/apt.conf.d/10periodic" ]]; then
|
||||
backup_file "/etc/apt/apt.conf.d/10periodic"
|
||||
fi
|
||||
|
||||
cat > /etc/apt/apt.conf.d/10periodic << 'EOF'
|
||||
// Planification des tâches APT automatiques
|
||||
APT::Periodic::Update-Package-Lists "1"; // Mettre à jour les listes quotidiennement
|
||||
APT::Periodic::Download-Upgradeable-Packages "1"; // Télécharger les paquets upgradables
|
||||
APT::Periodic::AutocleanInterval "7"; // Nettoyer le cache tous les 7 jours
|
||||
APT::Periodic::Unattended-Upgrade "1"; // Exécuter unattended-upgrade
|
||||
APT::Periodic::Verbose "0"; // Mode silencieux
|
||||
APT::Periodic::RandomSleep "300"; // Délai aléatoire pour éviter la charge simultanée
|
||||
EOF
|
||||
|
||||
# Configuration pour apt-listchanges (uniquement si le fichier existe)
|
||||
if [[ -f "/etc/apt/listchanges.conf" ]]; then
|
||||
backup_file "/etc/apt/listchanges.conf"
|
||||
sed -i 's/^frontend=.*/frontend=mail/' /etc/apt/listchanges.conf 2>/dev/null || true
|
||||
sed -i 's/^which=.*/which=both/' /etc/apt/listchanges.conf 2>/dev/null || true
|
||||
sed -i 's/^email_address=.*/email_address=root/' /etc/apt/listchanges.conf 2>/dev/null || true
|
||||
sed -i 's/^confirm=.*/confirm=0/' /etc/apt/listchanges.conf 2>/dev/null || true
|
||||
else
|
||||
# Créer une configuration minimale si le fichier n'existe pas
|
||||
cat > /etc/apt/listchanges.conf << 'EOF' 2>/dev/null || true
|
||||
[apt]
|
||||
frontend=mail
|
||||
email_address=root
|
||||
confirm=0
|
||||
save_seen=/var/lib/apt/listchanges.db
|
||||
which=both
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Configuration pour needrestart (gestion conditionnelle)
|
||||
if [[ -f "/etc/needrestart/needrestart.conf" ]]; then
|
||||
backup_file "/etc/needrestart/needrestart.conf"
|
||||
sed -i 's/^#\$nrconf{restart}.*/\$nrconf{restart} = '"'a'"';/' /etc/needrestart/needrestart.conf 2>/dev/null || true
|
||||
sed -i 's/^#\$nrconf{override_rc}.*/\$nrconf{override_rc} = '"'0'"';/' /etc/needrestart/needrestart.conf 2>/dev/null || true
|
||||
else
|
||||
# Créer le répertoire et le fichier si nécessaire
|
||||
mkdir -p /etc/needrestart/ 2>/dev/null || true
|
||||
cat > /etc/needrestart/needrestart.conf << 'EOF' 2>/dev/null || true
|
||||
# Configuration de needrestart
|
||||
$nrconf{restart} = 'a'; # Redémarrer automatiquement les services
|
||||
$nrconf{override_rc} = 0; # Ne pas modifier les scripts rc
|
||||
$nrconf{html_browser} = ''; # Pas de navigateur HTML
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Configuration du timer systemd (optionnel)
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
# Créer le répertoire pour les overrides
|
||||
mkdir -p /etc/systemd/system/apt-daily.timer.d/ 2>/dev/null || true
|
||||
|
||||
# Ne pas essayer de sauvegarder un fichier qui n'existe pas
|
||||
if [[ -f "/etc/systemd/system/apt-daily.timer" ]]; then
|
||||
backup_file "/etc/systemd/system/apt-daily.timer"
|
||||
fi
|
||||
|
||||
# Créer l'override
|
||||
cat > /etc/systemd/system/apt-daily.timer.d/override.conf << 'EOF' 2>/dev/null || true
|
||||
[Timer]
|
||||
OnCalendar=
|
||||
OnCalendar=*-*-* 3:00
|
||||
RandomizedDelaySec=1h
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Activer le service
|
||||
print_info "Activation du service unattended-upgrades..."
|
||||
|
||||
if systemctl is-enabled unattended-upgrades >/dev/null 2>&1; then
|
||||
systemctl restart unattended-upgrades 2>&1 | tee -a "$LOG_FILE" || true
|
||||
print_info "Service unattended-upgrades redémarré"
|
||||
else
|
||||
systemctl enable unattended-upgrades 2>&1 | tee -a "$LOG_FILE" || true
|
||||
systemctl start unattended-upgrades 2>&1 | tee -a "$LOG_FILE" || true
|
||||
print_info "Service unattended-upgrades activé et démarré"
|
||||
fi
|
||||
|
||||
# Vérification simple
|
||||
sleep 2
|
||||
|
||||
if systemctl is-active unattended-upgrades >/dev/null 2>&1; then
|
||||
print_success "Service unattended-upgrades actif"
|
||||
else
|
||||
print_warning "Service unattended-upgrades inactif (démarrage différé)"
|
||||
fi
|
||||
|
||||
# Tester la configuration (optionnel)
|
||||
if command -v unattended-upgrade >/dev/null 2>&1; then
|
||||
print_info "Test de configuration unattended-upgrades..."
|
||||
unattended-upgrade --dry-run --debug 2>&1 | grep -i "checking\|result" | head -5 | tee -a "$LOG_FILE" || true
|
||||
fi
|
||||
|
||||
# Afficher un résumé
|
||||
echo ""
|
||||
print_info "Configuration des mises à jour automatiques:"
|
||||
echo " ✓ Configuration unattended-upgrades appliquée"
|
||||
echo " ✓ Planification quotidienne configurée"
|
||||
echo " ✓ Mises à jour de sécurité activées"
|
||||
echo " ✓ Nettoyage automatique activé"
|
||||
echo ""
|
||||
|
||||
print_success "Mises à jour automatiques configurées"
|
||||
mark_step_done "$step_name"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# FONCTIONS PRINCIPALES
|
||||
# ==============================================================================
|
||||
|
|
|
|||
Loading…
Reference in New Issue