
Durcir le noyau Linux de son NAS selon les normes CIS Level 2
Au-delà du simple pare-feu
Un pare-feu et fail2ban ne couvrent que la surface. Le noyau Linux lui-même, avec ses paramètres par défaut permissifs, ses modules inutiles chargés en mémoire et ses points de montage sans restrictions, reste une passoire — et ces vecteurs d'attaque sont tous documentés et exploitables.
Les CIS benchmarks (Center for Internet Security) proposent deux niveaux : Level 1 pour les serveurs standard, Level 2 pour les environnements sensibles. Pour un NAS qui stocke photos de famille, backups et données domotiques, c'est Level 2. Configuration de référence ici : TerraMaster F4-424 sous Debian 13 (Trixie).
La collection devsec.hardening
Appliquer 200+ recommandations CIS à la main n'a pas de sens quand la collection Ansible devsec.hardening le fait déjà, maintenue et validée par la communauté.
L'organisation retenue découpe ça en rôles CIS spécialisés — cis_permissions, cis_accounts, cis_cron, cis_sudo, cis_tcpwrappers, cis_logging, cis_services, cis_ntp — chacun taggé et indépendant. N'exécuter que le logging tient en une commande Ansible.
Plus de 40 paramètres sysctl
Le fichier /etc/sysctl.d/99-hardening.conf concentre l'essentiel.
Protections mémoire et noyau
# Désactiver io_uring (vecteur d'attaque fréquent)
kernel.io_uring_disabled = 2
# Interdire le chargement dynamique de noyaux (kexec)
kernel.kexec_load_disabled = 1
# ASLR complet (randomisation de l'espace d'adressage)
kernel.randomize_va_space = 2
# Restreindre l'accès aux pointeurs noyau dans les logs
kernel.kptr_restrict = 2
# Restreindre dmesg aux utilisateurs root
kernel.dmesg_restrict = 1
# Interdire les core dumps pour les programmes SUID
fs.suid_dumpable = 0
# Restreindre l'accès aux événements perf
kernel.perf_event_paranoid = 3
# Désactiver les vsyscalls (vecteur ROP)
# (configuré via GRUB: vsyscall=none)
Protections réseau
# Reverse path filtering (anti-spoofing)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignorer les redirections ICMP
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# Ignorer les requêtes ICMP broadcast
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Protection contre les SYN flood
net.ipv4.tcp_syncookies = 1
# Interdire le routage source
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Désactiver le forwarding IPv6 (le NAS n'est pas un routeur)
net.ipv6.conf.all.forwarding = 0
# Logging des paquets martiens
net.ipv4.conf.all.log_martians = 1
Une quarantaine de paramètres au total, chacun documenté dans le benchmark CIS et fermant un vecteur précis.
GRUB : les paramètres de boot
Certains durcissements doivent être appliqués au chargement du noyau :
GRUB_CMDLINE_LINUX="slab_nomerge pti=on randomize_kstack_offset=on vsyscall=none debugfs=off"
- slab_nomerge : empêche la fusion des caches slab, ce qui limite les attaques par confusion de types
- pti=on : Page Table Isolation, la mitigation contre Spectre et Meltdown
- randomize_kstack_offset : la pile noyau est randomisée à chaque syscall
- vsyscall=none : élimine un gadget ROP connu
- debugfs=off : ferme le filesystem de debug du kernel
Blacklister les modules inutiles
Dans /etc/modprobe.d/hardening.conf :
# Systèmes de fichiers exotiques
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
# Protocoles réseau rarement utilisés
install dccp /bin/true
install sctp /bin/true
install rds /bin/true
install tipc /bin/true
# USB storage (désactivé sur un NAS headless)
install usb-storage /bin/true
L'astuce install <module> /bin/true est plus solide qu'un simple blacklist : un blacklist peut être contourné par des dépendances, alors que « installe /bin/true » ne fait rien, silencieusement. Un blacklist squashfs seul laisse le module se charger quand même.
Durcissement des points de montage
Dans /etc/fstab :
tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0
tmpfs /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0
- noexec : aucun binaire ne peut s'exécuter, donc pas de payload déposé puis lancé
- nosuid : bits SUID/SGID ignorés
- nodev : création de fichiers device interdite
Pour /proc, hidepid=2 empêche les utilisateurs lambda de voir les processus des autres :
proc /proc proc defaults,hidepid=2 0 0
AppArmor en mode enforce
AppArmor fournit du MAC (Mandatory Access Control) : même compromis, un processus ne peut toucher qu'à ce que son profil autorise. Sur Debian 13, AppArmor est activé par défaut mais souvent en mode « complain » (log uniquement). Le hardening le passe en enforce :
aa-enforce /etc/apparmor.d/*
Une commande, mais c'est la différence entre « on sait ce qui s'est passé » et « on empêche que ça se passe ».
Politiques de mots de passe (NIST SP 800-63B)
# /etc/security/pwquality.conf
minlen = 15 # 15 caractères minimum
minclass = 3 # Au moins 3 classes de caractères
maxrepeat = 3 # Max 3 caractères identiques consécutifs
# /etc/login.defs
PASS_MAX_DAYS 365 # Expiration à 365 jours
PASS_MIN_DAYS 1 # 1 jour minimum entre les changements
LOGIN_RETRIES 3 # 3 tentatives de login
LOGIN_TIMEOUT 60 # Timeout de 60 secondes
UMASK 077 # Permissions restrictives par défaut
Plus le verrouillage de compte après 3 échecs avec un délai de 15 minutes via PAM (pam_faillock), et les core dumps globalement désactivés dans /etc/security/limits.conf.
Mises à jour automatiques
unattended-upgrades applique les correctifs de sécurité quotidiennement, avec reboot automatique à 4 h du matin si nécessaire :
# /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
Un NAS non patché finira compromis. Le créneau de 4 h évite de couper un usage réel.
AIDE : surveiller l'intégrité des fichiers
AIDE (Advanced Intrusion Detection Environment) compare l'état du système à une baseline et signale tout ce qui a changé :
# Initialisation de la base
aide --init
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Vérification quotidienne (via cron)
aide --check
Si un binaire système change sans raison légitime — et il y en a peu — AIDE le voit.
Audit logging avec auditd
auditd trace les événements de sécurité, ici avec plus de 40 règles :
# /etc/audit/rules.d/hardening.rules
# Surveillance des changements d'authentification
-w /etc/passwd -p wa -k auth_changes
-w /etc/shadow -p wa -k auth_changes
-w /etc/group -p wa -k auth_changes
# Surveillance de sudo
-w /etc/sudoers -p wa -k sudo_changes
-w /etc/sudoers.d/ -p wa -k sudo_changes
# Chargement de modules noyau
-a always,exit -F arch=b64 -S init_module -S delete_module -k modules
# Changements réseau
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k network
# Surveillance des packages
-w /usr/bin/dpkg -p x -k packages
-w /usr/bin/apt -p x -k packages
# Surveillance de systemd
-w /etc/systemd/ -p wa -k systemd
-w /usr/lib/systemd/ -p wa -k systemd
Ces logs sont ce qui permet, après coup, de savoir qui a fait quoi, quand et avec quel outil — le point de départ de toute investigation.
Ce qu'il faut retenir
CIS Level 2 sur un NAS domestique peut sembler excessif, mais chaque paramètre ferme un vecteur réel et documenté. Grâce à devsec.hardening et aux rôles Ansible, l'application tient en une commande et se maintient sans effort. Le vrai travail est de comprendre ce que chaque règle fait : appliquer un benchmark sans le lire ne protège pas grand-chose.
Articles similaires