Cette page récapitule quelles règles ANSSI s’activent , selon le niveau et
la catégorie d’un hôte. C’est la référence à consulter avant de monter le
durcissement d’une machine.
Comprendre d’abord
Les notions employées ici (niveaux, catégories, étiquettes, MAC, egress…) sont
expliquées dans Notions de
sécurité .
darkone . system . security = {
level = " intermediary " ; # minimal | intermediary | reinforced | high
category = " server " ; # base | client | server
Les niveaux sont cumulatifs : intermediary ajoute ses règles à celles de
minimal, et ainsi de suite. La catégorie ajoute les règles propres au poste
(client) ou au serveur (server).
Profil Catégorie conseillée Pourquoi minimal, portablebaseSocle universel desktop, laptopclientÉcran, USB, session interactive server, gateway, hcs, vmserverServices exposés, réseau
Aujourd’hui : base partout
Le rattachement automatique profil → catégorie n’est pas encore actif. Tous les
hôtes sont en minimal / base par défaut. Pour appliquer une catégorie, posez
category à la main sur l’hôte concerné.
Chaque colonne indique l’état de la règle à ce niveau (les niveaux étant
cumulatifs). Légende :
Icône Signification ✅ Active à ce niveau ⚠️ Partielle (voir la note) ❌ Pas encore active à ce niveau
Code Règle Min Inter Renf Élevé R3Secure Boot UEFI (si supporté) ❌ ⚠️ ⚠️ ⚠️ R5Mot de passe du chargeur d’amorçage ❌ ⚠️ ⚠️ ⚠️ C6Chiffrement disque LUKS2 ❌ ⚠️ ⚠️ ⚠️ R7IOMMU activé ❌ ❌ ✅ ✅ R29/boot restreint❌ ❌ ✅ ✅ R6Protection cmdline et initramfs ❌ ❌ ❌ ✅
R3, R5, C6 : avertissement, pas de reconfiguration de l’amorçage
À partir de intermediary, ces règles émettent un avertissement quand la
protection n’est pas détectée, mais ne reconfigurent pas le démarrage. Le Secure
Boot (lanzaboote, enrôlement de clés) et le chiffrement LUKS se déclarent dans
la configuration disque de l’hôte (disko) ; le module ne fait que signaler
leur absence. Le futur checkScript vérifiera leur état réel.
Code Règle Min Inter Renf Élevé R8Options mémoire sur la ligne de commande ❌ ✅ ✅ ✅ R9sysctls de durcissement ❌ ✅ ✅ ✅ R11Yama : ptrace restreint ❌ ✅ ✅ ✅ R10Chargement de modules désactivé ❌ ❌ ✅ ✅ R60Noyau linux_hardened ❌ ❌ ✅ ✅ C1Patchs linux-hardened ❌ ❌ ❌ ✅ C2LSM Lockdown ❌ ❌ ❌ ✅ R15–R27Durcissement à la compilation ❌ ❌ ❌ ✅
R9 : les espaces de noms utilisateur restent autorisés
La clé historique kernel.unprivileged_userns_clone vient d’un correctif
Debian, absente d’un noyau mainline : l’écrire met systemd-sysctl en échec.
L’équivalent mainline user.max_user_namespaces = 0 casse Flatpak, bubblewrap
et Podman rootless. Il est donc optionnel :
darkone.security.kernel-params.restrictUserns = true, à réserver aux serveurs
sans bac à sable applicatif.
Code Règle Min Inter Renf Élevé R30Comptes inutilisés désactivés ✅ ✅ ✅ ✅ R31Mots de passe robustes ✅ ✅ ✅ ✅ R68Stockage des mots de passe en yescrypt ✅ ✅ ✅ ✅ R32Verrouillage sur inactivité ❌ ✅ ✅ ✅ R33Traçabilité des actions admin ❌ ✅ ✅ ✅ R34Comptes de service sans shell ❌ ✅ ✅ ✅ R35Comptes de service uniques ❌ ✅ ✅ ✅ R67PAM distant sécurisé ❌ ⚠️ ⚠️ ⚠️ R69Bases d’utilisateurs en TLS ❌ ⚠️ ⚠️ ⚠️ R70Comptes système ≠ annuaire ❌ ⚠️ ⚠️ ⚠️ C10Limites de session (nproc, nofile) ❌ ✅ ✅ ✅
R69, R70 : annuaire distant différé
Ces règles ne concernent qu’un annuaire distant (SSSD/nslcd), non utilisé
par DNF aujourd’hui ; leur volet TLS est différé (futur checkScript).
R32 : déconnexion des sessions inactives
TMOUT=600 ferme toute session console ou SSH restée dix minutes sans commande,
sur bash comme sur zsh — DNF fait de zsh le shell de connexion par défaut,
et la variable n’était posée que pour bash. Un tmux ou un screen laissé au
premier plan tombe avec la session.
La variable est posée readonly : elle ne se désarme pas en session. Un poste
qui garde des terminaux au long cours (ferme de compilation, outillage
d’agents) règle darkone.security.users.idleTimeout = 0, ce qui retire le
délai TTY sans toucher au verrouillage GNOME.
R67 : pam_faillock verrouille vraiment les comptes
Trois mots de passe erronés verrouillent le compte 15 minutes, sur login,
su, sudo et, via la sous-pile login, l’écran de connexion GNOME. La
pile est complète : preauth refuse, authfail compte, la règle account
bloque un compte déjà verrouillé. Les deux règles auth encadrent le
pam_unix de chaque service ; leur rang est calculé, car il diffère d’une
pile à l’autre (11700 sur su/sudo, 13100 sur login).
sshd en est volontairement exclu : DNF interdit l’authentification par mot de
passe, donc faillock n’y compterait jamais rien. Sa règle account ne
saurait qu’y refuser une session de secours par clé pour un verrou acquis à la
console. L’accès de maintenance reste donc ouvert en toutes circonstances, et
nix (sans credential mot de passe) ne peut pas être verrouillé.
Gardez tout de même une session root ouverte au premier déploiement et
connaissez le retour : faillock --user <login> --reset. Réglages :
darkone.security.pam.faillock.deny et .unlockTime. root n’est jamais
verrouillé.
Code Règle Min Inter Renf Élevé R39Directives sudo durcies ❌ ✅ ✅ ✅ R40Cibles sudo non-root ❌ ✅ ✅ ✅ R42Interdiction des négations ❌ ✅ ✅ ✅ R44sudoedit pour l’édition❌ ✅ ✅ ✅ R38Groupe sudo dédié ❌ ❌ ✅ ✅ R41Limitation des overrides NOEXEC ❌ ❌ ✅ ✅
R39 : sans noexec ni requiretty
Ces deux directives sont incompatibles avec un déploiement piloté : colmena
escalade en sudo -H -- sans PTY, et switch-to-configuration lance des
processus fils. R39 s’appuie donc sur use_pty, log_input et log_output,
qui portent la traçabilité recherchée. Les captures de session s’accumulent dans
/var/log/sudo-io, tourné chaque semaine sur 12 archives.
Code Règle Min Inter Renf Élevé R53Détection des fichiers sans propriétaire ✅ ✅ ✅ ✅ R54Sticky bit sur /tmp et /var/tmp ✅ ✅ ✅ ✅ R56Détection des setuid hors liste blanche ✅ ✅ ✅ ✅ R14sysctls système de fichiers ❌ ✅ ✅ ✅ R28Partitionnement et options de montage ❌ ✅ ✅ ✅ R50Restriction des fichiers sensibles ❌ ✅ ✅ ✅ R52Permissions des sockets et tubes nommés ❌ ⚠️ ⚠️ ⚠️ R55Répertoires temporaires par utilisateur ❌ ⚠️ ⚠️ ⚠️ R36UMASK 0077❌ ❌ ✅ ✅ R57setuid root minimal (capabilities)❌ ❌ ✅ ✅
R14 : binfmt_misc conservé sur les hôtes qui émulent
Couper binfmt_misc casse la construction croisée (images aarch64 des
Raspberry Pi). La coupure est levée d’office quand boot.binfmt.emulatedSystems
n’est pas vide ; l’étiquette needs-binfmt reste utile pour les autres cas
(Java, qemu-static).
R28 : /tmp non exécutable
/tmp est un tmpfs en nosuid,nodev,noexec, dimensionné par
boot.tmp.tmpfsSize (25 % de la RAM par défaut). R28 est propriétaire du
montage : boot.tmp.useTmpfs est forcé à false, sinon l’unité tmp.mount
qu’il génère — sans noexec — l’emporterait silencieusement sur /etc/fstab.
noexec interdit l’exécution directe et dlopen. Il casse donc tout outil
qui exécute ce qu’il vient de décompresser (pip, cargo, gcc) et tout runtime
qui extrait ses bibliothèques natives dans /tmp (Bun, Electron, outillage
d’agents). Les compilations Nix sont couvertes, le démon basculant sur
/var/tmp, mais un outil interactif peut demander
export TMPDIR=$XDG_RUNTIME_DIR.
Deux sorties de secours, par hôte :
Option Effet darkone.security.filesystem.tmpNoexec = falsegarde le tmpfs et nosuid,nodev, retire noexec darkone.security.filesystem.tmpfs = falselaisse /tmp sur son système de fichiers d’origine (données persistantes, pas de RAM consommée)
R28, R52, R55 : services et partitions désignés
R28 durcit aussi /proc (hidepid=2) et /dev/shm. Le groupe proc, qui
donne le droit de voir les processus des autres, est peuplé des membres de
wheel, sans quoi ps, htop et le moniteur GNOME n’afficheraient plus rien
aux administrateurs eux-mêmes. Les options sur /var/log, les options sur /var/log,
/srv, /opt, /home s’ajoutent via darkone.security.filesystem.extraMountHardening
(partitions séparées requises). R52 (mode 0750 des répertoires d’exécution)
et R55 (/tmp privé par service) s’appliquent aux unités listées dans
darkone.security.services.hardenedUnits — vide par défaut. Voir R63.
Code Règle Min Inter Renf Élevé R62Services obsolètes coupés ✅ ✅ ✅ ✅ R63Capacités des services réduites ❌ ⚠️ ⚠️ ⚠️ R37Contrôle d’accès obligatoire (MAC) ❌ ❌ ✅ ✅ R45Profils AppArmor ❌ ❌ ✅ ✅ R64Privilèges de service restreints ❌ ❌ ✅ ✅ R65Isolation des services (namespaces) ❌ ❌ ✅ ✅ R66Durcissement des conteneurs ❌ ❌ ❌ ✅
R63 : bac à sable opt-in par service
Le confinement systemd complet (ProtectSystem=strict, filtres d’appels
système, MemoryDenyWriteExecute, UMask=0027…) s’applique aux unités déclarées
dans darkone.security.services.hardenedUnits. Vide par défaut : un
durcissement aveugle casserait des services. La liste agit comme un plancher ,
surchargeable par unité, et needs-jit lève MemoryDenyWriteExecute pour les
moteurs JIT.
Code Règle Min Inter Renf Élevé R80Surveillance des ports en écoute ✅ ✅ ✅ ✅ C4Pare-feu en refus par défaut ⚠️ ⚠️ ✅ ✅ R12sysctls réseau IPv4 ❌ ✅ ✅ ✅ R13Désactivation d’IPv6 (sur demande) ❌ ⚠️ ⚠️ ⚠️ C5Durcissement OpenSSH ❌ ✅ ✅ ✅ C7Synchronisation horaire NTS ❌ ✅ ✅ ✅ C8Résolveur DNS sécurisé (DNSSEC, DoT) ❌ ✅ ✅ ✅ R79Services exposés durcis (serveur) ❌ ✅ ✅ ✅ R78Isolation des services réseau (serveur) ❌ ❌ ✅ ✅
C4 partielle aux deux premiers niveaux
Au niveau minimal et intermediary, C4 couvre le filtrage entrant
(refus par défaut). Le filtrage sortant (egress) s’ajoute à partir de
reinforced.
C5 : ni tunnel, ni agent, ni ssh -J
Tunnels TCP, transfert d’agent et X11 sont coupés. ProxyJump tombe avec eux :
ssh -J ouvre un canal direct-tcpip, c’est-à-dire exactement ce que
AllowTcpForwarding refuse. L’accès d’administration se fait en direct sur le
tailnet , jamais par rebond.
Sur le tailnet, le SSH suit le poste
La politique d’accès du tailnet n’ouvre le port 22 qu’aux postes d’administration
et aux appareils déclarés dans adminDevices : un compte administrateur ne
suffit pas. Voir Politique d’accès .
R13 : couper IPv6 se demande explicitement
Une étiquette d’exclusion ne sait que retirer une règle. no-ipv6 rendait
donc R13 active par défaut et coupait IPv6 sur toute la flotte. La désactivation
passe désormais par darkone.security.kernel-params.disableIpv6 (false par
défaut) ; ANSSI préfère de toute façon durcir IPv6 plutôt que le supprimer.
R12 : filtrage de chemin inverse adapté au rôle
Le mode strict (rp_filter = 1) jette tout retour asymétrique. Un routeur de
sous-réseau tailscale annonce ses routes sans SNAT
(--snat-subnet-routes=false) : c’est exactement ce cas. Les hôtes isGateway
ou isExitNode passent en mode souple (2), les autres restent stricts.
R79 : chaque service exposé doit avoir son filtre
fail2ban tourne sur le backend systemd : une prison exige une définition
filter.d et un journalmatch, sinon le démon refuse de démarrer — et
emporte la prison sshd avec lui. exposedServices est donc vérifié à
l’évaluation contre darkone.security.network.filters. Fournis aujourd’hui :
sshd (livré par fail2ban) et vaultwarden. Caddy, Matrix et Kanidm réclament
des motifs écrits sur journaux réels.
Code Règle Min Inter Renf Élevé R71Journalisation persistante scellée ❌ ❌ ✅ ✅ R72Journaux dédiés par service ❌ ❌ ✅ ✅ R73auditd avec règles ANSSI ❌ ❌ ✅ ✅ C9Désactivation des core dumps ❌ ❌ ✅ ✅ R76Scellement et vérification d’intégrité ❌ ❌ ❌ ✅ R77Protection de la base scellée ❌ ❌ ❌ ✅
Code Règle Min Inter Renf Élevé C11Bannières légales d’accès ✅ ✅ ✅ ✅ C12cron / at restreints✅ ✅ ✅ ✅ R61Mises à jour régulières ⚠️ ⚠️ ⚠️ ⚠️ R74Courrier local durci ❌ ✅ ✅ ✅ R75Alias de messagerie (root → admin) ❌ ✅ ✅ ✅ R51Rotation des secrets d’installation ❌ ❌ ✅ ✅ C3USBGuard (poste) ❌ ❌ ✅ ✅
Étiquette kernel-recompile
Le durcissement noyau du niveau high (R15 à R27, C1) implique de
recompiler le noyau. Sur une machine sans ce besoin, ajoutez
kernel-recompile à excludes pour l’ignorer.
Trois soupapes permettent d’ajuster une protection précise sans descendre le
niveau global.
Tags (excludes) : couper un groupe de règles incompatibles
(ex. needs-jit, needs-binfmt).
Exceptions (exceptions) : contourner une règle, justification
obligatoire.
Options d’activation : allumer une règle trop destructrice pour être
active par défaut (disableIpv6, restrictUserns).
Un tag ne sait que retirer
excludes et exceptions soustraient des règles ; aucun des deux ne peut
en ajouter une. Une règle dangereuse par défaut se pilote donc par une option
dédiée, jamais par l’absence d’un tag.
Le détail de ces soupapes est dans Notions de
sécurité .
Module en cours de stabilisation
Montez le niveau progressivement et testez chaque hôte avant la production.