5 points par GN⁺ 2025-08-20 | 1 commentaires | Partager sur WhatsApp
  • systemd fournit de puissantes fonctions de gestion des services, mais sa configuration par défaut est optimisée pour l’utilisabilité plutôt que pour la sécurité, d’où la nécessité d’appliquer des options de hardening dédiées
  • La commande systemd-analyze security permet d’analyser les indicateurs d’exposition en matière de sécurité pour l’ensemble des services ou pour un service précis, et d’établir des priorités
  • Il existe de nombreuses options de sécurité applicables au niveau de l’unité de service, modifiables individuellement via /etc/systemd/system/ServiceName.service.d/override.conf et autres fichiers similaires
  • Parmi les principales options figurent ProtectSystem, PrivateTmp, NoNewPrivileges, SystemCallFilter, MemoryDenyWriteExecute, qui limitent les privilèges des processus et l’accès aux ressources
  • Plutôt que de viser une sécurité parfaite, il est possible de réduire les risques en durcissant en priorité les services exposés vers l’extérieur, avec un effet également très bénéfique dans les environnements self-hosting

Vue d’ensemble de systemd

  • systemd propose une approche très aboutie et robuste pour la gestion des services
  • Toutefois, ses paramètres par défaut privilégient l’usage immédiat plutôt que la sécurité, et restent donc relativement permissifs
  • Ce document présente plusieurs options de renforcement de la sécurité applicables aux unités de service systemd et à podman quadlet, afin de réduire les possibilités de compromission et de limiter l’ampleur des dégâts en cas d’incident
  • Il ne s’agit pas d’un guide à appliquer uniformément à tous les services : chaque service exige des tests, une vérification des logs et des ajustements en fonction de ses caractéristiques et de ses besoins
  • La responsabilité de la sécurité de l’infrastructure incombe entièrement à l’exploitant ; ce document n’est qu’un outil de référence

Analyse de sécurité de systemd

  • La commande systemd-analyze security permet de vérifier l’état de sécurité global des services ou d’analyser la configuration détaillée d’un service donné (par ex. sshd.service)
    • La sortie inclut l’état des contrôles, le nom de la fonctionnalité, sa description et un score d’exposition ; plus l’Exposure est élevé, plus le risque est important
  • Les options de sécurité peuvent être ajoutées dans la section [Service] (systemd) ou [Container] (podman quadlet)
  • Il est recommandé de créer un fichier d’override via systemctl edit ServiceName.service ; en cas d’échec, il faut vérifier puis ajuster les autorisations nécessaires

Options de sécurité des services

  • systemd fournit divers mots-clés d’options de sécurité, consultables notamment via man systemd.exec 5, man capabilities 7, etc.
  • Options de sécurité représentatives
    • ProtectSystem → option qui limite le système de fichiers en lecture seule
    • ProtectHome → option qui bloque l’accès à /home, /root, /run/user
    • PrivateDevices → option qui bloque l’accès aux périphériques physiques et n’autorise que les périphériques virtuels comme /dev/null
    • ProtectKernelTunables, ProtectKernelModules, ProtectKernelLogs → options qui bloquent l’accès aux ressources du noyau
    • NoNewPrivileges → option qui empêche l’obtention de nouveaux privilèges via setuid/setgid, etc.
    • MemoryDenyWriteExecute → option qui empêche l’usage simultané de mémoire inscriptible et exécutable ; cela peut poser problème à certains langages avec JIT
    • SystemCallFilter → option qui limite les appels système autorisés ; en cas de violation, le processus peut être terminé ou recevoir un retour EPERM

Description de chaque option

  • ProtectSystem : avec le réglage strict, l’ensemble du système de fichiers est monté en lecture seule ; /dev, /proc, /sys nécessitent des options de protection distinctes
  • ReadWritePaths : permet de réautoriser l’écriture uniquement sur certains chemins
  • ProtectHome : bloque l’accès à /home, /root, /run/user
  • PrivateDevices : désactive l’accès aux périphériques physiques et n’autorise que des pseudo-périphériques comme /dev/null
  • ProtectKernelTunables : passe /proc et /sys en lecture seule
  • ProtectControlGroups : n’autorise qu’un accès en lecture seule aux cgroups
  • ProtectKernelModules : interdit le chargement explicite de modules du noyau
  • ProtectKernelLogs : restreint l’accès au tampon des logs du noyau
  • ProtectProc : avec invisible, masque dans /proc/ les processus appartenant à d’autres utilisateurs
  • ProcSubset : bloque dans /proc le contenu autre que certains éléments liés au PID
  • NoNewPrivileges : bloque toute nouvelle élévation de privilèges via setuid, setgid ou les capabilities du système de fichiers
  • ProtectClock : bloque l’écriture sur l’horloge système/matérielle
  • SystemCallArchitectures : avec native, n’autorise que les syscalls natifs comme x86-64
  • RestrictNamespaces : limite les namespaces spécifiques aux conteneurs
  • RestrictSUIDSGID : empêche le positionnement des bits setuid et setgid sur les fichiers
  • LockPersonality : empêche le changement de domaine d’exécution (utile seulement pour certaines anciennes applications)
  • RestrictRealtime : limite l’ordonnancement temps réel (nécessaire uniquement pour certains services spécialisés)
  • RestrictAddressFamilies : limite les familles d’adresses socket autorisées (par ex. AF_INET, AF_INET6, AF_UNIX, etc.)
  • MemoryDenyWriteExecute : bloque la création de nouvelles zones mémoire à la fois inscriptibles et exécutables (prudence pour les services utilisant du JIT)
  • ProtectHostname : interdit l’usage des syscalls sethostname, setdomainname
  • SystemCallFilter : permet de définir, service par service, les syscalls autorisés/interdits, avec un filtrage fin
    • Les groupes, syscalls individuels et modes autorisation/interdiction peuvent être ajustés
    • En cas de violation, il est aussi possible de renvoyer un code d’erreur comme EPERM au lieu de terminer le processus
    • La liste complète est disponible via systemd-analyze syscall-filter ou man systemd.exec(5)
    • Le préfixe ~ permet de négativer l’ensemble d’une liste (ex. CapabilityBoundingSet=~CAP_SETUID etc.)

Processus d’ajustement des restrictions SystemCallFilter

  • Avec auditd, il est possible de consulter les logs pour voir quel syscall a été bloqué lorsqu’un service échoue
    • Exécuter sudo ausearch -i -m SECCOMP -ts recent, puis vérifier la valeur du syscall
    • Il est ensuite possible d’ajouter ce syscall ou le groupe concerné à SystemCallFilter afin de résoudre le problème progressivement

Priorités d’application du hardening et conseils d’exploitation

  • Il n’est pas nécessaire de tout appliquer à tous les services
  • Le modèle de menace et la gestion du risque sont essentiels ; en particulier, les services exposés vers l’extérieur (httpd, nginx, ssh, etc.) doivent être considérés en priorité
  • Il est aussi efficace d’appliquer ces mesures de façon préventive aux commandes personnalisées, aux unités timer (remplaçantes de cron), etc.
  • Plus un service est simple, plus il est généralement possible d’effectuer des ajustements fins

Checklist : combinaison d’options de sécurité recommandée (priorité d’application initiale)

  • ProtectSystem=strict
  • PrivateTmp=yes
  • ProtectHome=yes ou ProtectHome=tmpfs
  • ProtectClock=yes, ProtectKernelLogs=yes, ProtectKernelModules=yes
  • RestrictSUIDGUID=yes
  • UMask=0077
  • LockPersonality=yes
  • RestrictRealtime=yes
  • MemoryDenyWriteExecute=yes
  • DynamicUser=yes ou définir User sur un utilisateur spécifique autre que root
  • Les éléments ci-dessus constituent en général une combinaison utilisable sans presque aucun impact sur le service
  • L’ajout d’un filtrage des syscalls (SystemCallFilter) nécessite en revanche des tests détaillés

Exemple de configuration Traefik

  • Il s’agit d’un exemple d’exécution d’un service Traefik conteneurisé avec systemd quadlet, en appliquant de nombreuses options de sécurité
    • ProtectSystem=full, ProtectHome=yes, SystemCallFilter=@system-service @mount @privileged, etc.
    • CapabilityBoundingSet=~CAP_SETUID CAP_SETPCAP retire certains privilèges spécifiques
    • RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK, etc., applique des limitations d’accès réseau

Conclusion

  • Les options de hardening de systemd constituent un moyen pratique à garder dans la boîte à outils de tout administrateur système Unix
  • Il ne faut pas les considérer comme une solution de sécurité parfaite, mais comme un outil de réduction du risque ; il n’est pas nécessaire d’appliquer indistinctement des réglages de sécurité à tous les services
  • Elles peuvent être particulièrement utiles aux administrateurs d’environnements self-hosting pour améliorer nettement leur niveau de sécurité
  • En privilégiant la « praticité plutôt que la perfection », il est recommandé de les appliquer au moins partiellement, dans la mesure adaptée au travail et à l’environnement

1 commentaires

 
GN⁺ 2025-08-20
Avis Hacker News
  • Je trouve intéressant qu’on puisse mettre en place un durcissement automatisé des services systemd via du profilage strace
    https://github.com/desbma/shh

    • J’ai trouvé une bonne méthode : ProtectSystem= n’est pas utilisé dans l’exemple, mais avec
      TemporaryFileSystem=/:ro, BindReadOnly=/usr/bin/binary /lib /lib64 /usr/lib usr/lib64
      on peut n’inclure que le binaire voulu et les chemins qu’on souhaite laisser en lecture
      ProtectSystem= n’est actuellement pas compatible avec ce comportement
      Voir plus de détails ici

    • Je pense que cette approche peut poser problème pour les services qui ont besoin d’actions supplémentaires en cas d’erreur, comme l’envoi d’un e-mail

  • Par rapport à l’article d’hier sur le durcissement de systemd, celui-ci est bien plus réaliste et rempli de bons conseils applicables immédiatement
    J’avais essayé de donner des exemples plus concrets dans les commentaires de l’article d’hier, mais l’article d’aujourd’hui organise tout cela de façon bien plus claire et explique comment renforcer rapidement et facilement l’isolation et la sécurité avec systemd
    Je trouve que c’est un excellent article
    Je laisse aussi celui d’hier en référence
    https://us.jlcarveth.dev/post/hardening-systemd.md
    https://news.ycombinator.com/item?id=44928504

    • Ce serait bien de corriger le problème de certificat du site
      Sur certains navigateurs, l’accès est tout simplement impossible à cause de l’erreur de certificat
  • Merci pour le partage
    On peut vérifier la sécurité des unités utilisateur systemd en utilisant systemd-analyze avec l’option --user (systemd-analyze --user security)
    J’utilise davantage systemd depuis que j’ai migré des conteneurs vers Podman, et cet outil sera très utile pour améliorer la sécurité des unités systemd et des services de conteneurs

  • Les anciens scripts init étaient tous différents, donc ce genre de durcissement cohérent était impossible

    • Bien sûr, ce type de durcissement était aussi faisable avec les anciens scripts init, mais systemd aide à exploiter facilement les bonnes fonctionnalités du noyau d’une manière standard et cohérente
      Je suis arrivé assez tard dans l’écosystème Linux, donc j’ai du mal à imaginer un système sans systemd, et les systèmes sans systemd me paraissaient très peu pratiques à administrer
      J’ai récemment découvert l’outil unshare, qui permet de faire des expériences comme remonter tout /nix en RW sans affecter les autres processus
      L’ergonomie de systemd est un peu rugueuse, mais honnêtement, pour moi, la seule alternative serait Windows
  • Je me demande pourquoi les distributions Linux n’activent pas davantage de ces options de sécurité par défaut
    Je me demande s’il y a des inconvénients à un durcissement conservateur
    Pour beaucoup d’utilisateurs, il y a peut-être simplement trop de réglages et trop de complexité

    • Si on modifie les réglages de façon trop agressive, on risque de casser des configurations existantes sans le vouloir
      Par exemple, si on durcit NetworkManager, il faut vérifier un par un que les connexions IPv4 et IPv6 fonctionnent toujours, que les modes dns=systemd-resolved et dns=default marchent correctement, ainsi que l’intégration avec ModemManager et le cellulaire, les plugins openvpn ou cisco anyconnect, les hooks NetworkManager-dispatcher, etc.
      Il y a aussi la question de savoir combien de mainteneurs de distributions peuvent être certains jusqu’où ils peuvent changer les options d’un paquet sans casser plus de 0,01 % des environnements utilisateurs
      Si ces flags sont gérés par la distribution, chaque release upstream apporte en prime des problèmes de compatibilité ; et si c’est upstream qui les définit, la rétrocompatibilité oblige à être encore plus prudent

    • Cette question ressemble à « pourquoi les distributions n’activent-elles pas par défaut des politiques MAC (comme SELinux) plus strictes ? »
      Il serait sans doute préférable de restreindre davantage quelque chose comme sshd, mais

      1. le coût initial de développement pour les appliquer
      2. le coût de traitement des bugs spécifiques à toutes sortes d’environnements utilisateurs
      3. le coût de maintenance continue pour suivre les changements côté distribution et upstream
        font que c’est une lourde charge pour les distributions majeures
        C’est pareil pour SELinux et AppArmor : beaucoup de mainteneurs jugent que le retour sur investissement est faible
    • Une autre raison importante est l’absence de moyens ou de ressources pour faire des tests d’intégration, paramètre par paramètre, sur le bon fonctionnement des services système critiques
      Discussion connexe
      https://news.ycombinator.com/item?id=29995566
      Les résultats de systemd-analyze security diffèrent selon les distributions
      desbma/shh génère automatiquement, à partir de ce qui est collecté par strace, des règles par unité comme SyscallFilter, un peu à la manière de audit2allow pour SELinux
      Mais installer strace en production peut faire débat
      https://github.com/desbma/shh

    • Je ne sais pas trop non plus, mais certains réglages sont récents, donc beaucoup d’utilisateurs ne les connaissent peut-être pas encore
      Il n’y a pas que des experts systemd, et activer certains paramètres peut aussi risquer de ne pas fonctionner correctement sur d’anciennes versions de systemd
      Il existe diverses fonctions comme SELinux ou AppArmor, mais beaucoup de distributions, de développeurs et d’utilisateurs ne ressentent tout simplement pas le besoin de les rendre automatiques

  • Il y a tellement d’options de durcissement que je trouverais utile d’avoir un dépôt regroupant des exemples génériques de durcissement par type de service
    Les utilisateurs réutilisent souvent des scripts de durcissement communs, mais on se rend parfois compte qu’il faut au contraire élargir un peu les permissions pour éviter les cas particuliers

    • Lorsqu’on empaquette pour une distribution où le support upstream est limité, comme nixpkgs,
      le plus utile est de regarder comment les distributions grand public empaquettent et durcissent les logiciels
      Ces méthodes de durcissement sont souvent déjà bien testées ; donc si vous cherchez des exemples, par exemple pour postgresql, le mieux est de partir des paquets Debian, Ubuntu ou RHEL
  • L’une des excellentes fonctions de sécurité offertes par systemd est la gestion des credentials
    Cela permet de transmettre des secrets à une application de manière plus sûre qu’en les stockant dans des variables d’environnement ou dans le système de fichiers
    Dans des environnements sans Vault, par exemple pour des projets personnels, je préfère toujours cette méthode
    J’ai même créé moi-même un package Go qui s’intègre à cette fonctionnalité
    credentials dans systemd
    package credential-go

    • J’ai l’impression que c’est un peu la culture nodejs ou npm où même deux lignes de code deviennent un package
      En pratique, c’est juste

      dir, err := os.Getenv("CREDENTIALS_DIRECTORY")
      cred, err := os.ReadFile(filepath.Join(dir, "name"))
      

      ce n’est même pas plus compliqué que left-pad
      Il me semblait qu’au sein de la communauté Go, on valorisait plutôt la réduction des dépendances et l’évitement des abstractions inutiles (comme les appels de fonction)
      Ce genre de logique simple, tout le monde l’écrivait normalement directement sur le moment

    • Je me demande comment ce mode de transmission des credentials empêche l’héritage des secrets par les processus enfants forkés

  • Article vraiment utile
    J’aime aussi la liste des différentes options systemd et les conseils du style « consultez le man et bonne chance »
    systemd est vraiment excellent et j’ai envie de le déployer activement sur mes serveurs

  • Petit détail, mais la graphie correcte est bien systemd dans le titre
    Ce n’est ni SystemD, ni system D, ni system d, mais bien systemd
    La raison est que cela vient de « system daemon », conformément à la tradition Unix/Linux qui utilise un d minuscule en fin de nom

    • Fait intéressant
      J’ai souvent vu systemD, et je me demande pourquoi cette forme s’est autant répandue
  • L’astuce pour déboguer les problèmes de syscalls dans systemd est vraiment utile