E-NO
Sécurité systemd 7 min de lecture

Durcissement de la sécurité systemd avec exemples pratiques : guide pratique

calendar_today Publié : 2026-07-25
update Dernière mise à jour : 2026-07-25
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Durcissement de la sécurité systemd avec exemples pratiques : guide pratique ».

Introduction

Les unités systemd durcies réduisent la surface d'attaque des services Linux en appliquant par défaut le moindre privilège, en isolant fichiers et périphériques, en limitant l'accès réseau et en restreignant fortement les actions des processus. Ce guide présente un workflow pratique et des exemples copiables applicables à de nouveaux ou d'anciens services. Vous apprendrez à exécuter en tant qu'utilisateur sans privilèges, verrouiller l'accès au système de fichiers, restreindre les capacités et les appels système, gérer les secrets en toute sécurité, contrôler l'exposition réseau et valider les modifications avec des vérifications sûres.

Aperçu du workflow

  • Profiler le service : identifier l'utilisateur sous lequel il s'exécute, les fichiers qu'il doit écrire, les ports sur lesquels il écoute et les besoins noyau particuliers (par ex. CAP_NET_BIND_SERVICE pour les ports inférieurs à 1024, ou CAP_DAC_OVERRIDE pour les ACL du système de fichiers).
  • Réduire les privilèges : s'exécuter comme un utilisateur dédié, supprimer les capacités Linux et bloquer l'élévation de privilèges avec NoNewPrivileges=yes.
  • Verrouiller le système de fichiers : tout rendre en lecture seule par défaut avec ProtectSystem=strict, puis autoriser explicitement les chemins d'écriture via StateDirectory=, CacheDirectory=, LogsDirectory= ou ReadWritePaths=.
  • Isoler les périphériques et les espaces de noms : retirer l'accès aux périphériques de l'hôte (PrivateDevices=yes) et aux espaces de noms non sûrs (RestrictNamespaces=yes).
  • Limiter les appels système et l'exécution mémoire : appliquer des filtres d'appels système (SystemCallFilter=@system-service) et désactiver les violations W^X (MemoryDenyWriteExecute=yes).
  • Contraindre le réseau : tout refuser avec IPAddressDeny=any, puis autoriser explicitement seulement les adresses et familles requises.
  • Gérer les secrets correctement : transmettre les secrets via LoadCredential= et les lire depuis $CREDENTIALS_DIRECTORY, jamais comme variables d'environnement en ligne.
  • Vérifier et itérer : charger l'unité, lancer systemd-analyze security, tester la fonctionnalité, examiner les journaux pour les refus et revenir proprement si nécessaire.

Exemples pratiques de durcissement

Utilisez ces extraits comme point de départ et adaptez-les à votre service.

1) Modèle de service durci de base

Ce modèle suppose un service TCP simple qui se lie à localhost sur le port 8080 et a besoin d'écrire l'état et les journaux.

# /etc/systemd/system/myapp.service
[Unit]
Description=MyApp (durci)
After=network-online.target
Wants=network-online.target

[Service]
# Commande
ExecStart=/usr/local/bin/myapp --listen 127.0.0.1:8080

# Moindre privilège
User=myapp
Group=myapp
UMask=0077
NoNewPrivileges=yes
CapabilityBoundingSet=
AmbientCapabilities=

# Protections du système de fichiers
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes

# Emplacements d'écriture explicites gérés par systemd
StateDirectory=myapp
CacheDirectory=myapp
LogsDirectory=myapp
# Si vous devez autoriser des écritures ailleurs, les déclarer explicitement
# ReadWritePaths=/var/lib/myapp /var/log/myapp

# Durcissement mémoire et personnalité
MemoryDenyWriteExecute=yes
LockPersonality=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
SystemCallArchitectures=native
# Liste d'autorisation conservatrice ; ajustez pour votre application
SystemCallFilter=@system-service

# Contrôles réseau : refuser par défaut, autoriser seulement la boucle locale
IPAddressDeny=any
IPAddressAllow=127.0.0.1
IPAddressAllow=::1
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

# Environnement et identifiants
EnvironmentFile=-/etc/myapp/myapp.env
# Fournir les secrets via les identifiants ; lire en utilisant $CREDENTIALS_DIRECTORY
# Le fichier doit appartenir à root:root, mode 0400 ou plus strict
LoadCredential=api_token:/etc/credentials/myapp_api_token

# Politique de redémarrage
Restart=on-failure
RestartSec=2s

[Install]
WantedBy=multi-user.target

Notes :

  • StateDirectory=, CacheDirectory= et LogsDirectory= créent des répertoires dédiés sous /var/lib/, /var/cache/ et /var/log/ appartenant à l'utilisateur du service avec le mode 0750. Préférez-les aux chemins manuels.
  • ProtectSystem=strict rend /usr, /boot et /etc en lecture seule. Autorisez les écritures nécessaires avec les options XDirectory= ou ReadWritePaths=.
  • CapabilityBoundingSet= et AmbientCapabilities= vides suppriment toutes les capacités sauf si explicitement requises.
  • IPAddressDeny=any combiné avec IPAddressAllow= contraint tout le trafic réseau entrant et sortant aux adresses listées.
  • SystemCallFilter=@system-service utilise un profil conservateur. Si le service casse, inspectez journalctl -u myapp.service -b pour les refus SECCOMP et ajoutez les groupes d'appels système spécifiques dont vous avez besoin (par ex. @system-service @network-io).

2) Service sans aucun accès réseau

# /etc/systemd/system/batch-job.service
[Unit]
Description=Tâche batch nocturne (isolée)
After=local-fs.target

[Service]
ExecStart=/usr/local/bin/batch-job
User=batch
Group=batch
UMask=0077
NoNewPrivileges=yes
CapabilityBoundingSet=
AmbientCapabilities=
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
RestrictSUIDSGID=yes
MemoryDenyWriteExecute=yes
LockPersonality=yes
RestrictNamespaces=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
# Isolation réseau stricte
PrivateNetwork=yes
RestrictAddressFamilies=AF_UNIX
IPAddressDeny=any
StateDirectory=batch-job
LogsDirectory=batch-job
Restart=on-failure

3) Transmettre les secrets en toute sécurité avec les identifiants

Évitez de placer des secrets bruts directement dans les fichiers d'unité. Utilisez plutôt LoadCredential= et lisez-les depuis le répertoire des identifiants.

# /etc/systemd/system/report.service
[Unit]
Description=Générateur de rapports

[Service]
ExecStart=/usr/local/bin/report --token-file "$CREDENTIALS_DIRECTORY/api_token"
User=report
Group=report
NoNewPrivileges=yes
CapabilityBoundingSet=
AmbientCapabilities=
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
LoadCredential=api_token:/etc/credentials/report_api_token
StateDirectory=report
LogsDirectory=report

Sur le disque :

  • /etc/credentials/report_api_token doit appartenir à root:root avec le mode 0400.
  • Le service lit le secret depuis $CREDENTIALS_DIRECTORY/api_token à l'exécution.

4) Vérifications et validation sûres

# Syntaxe et intégrité de l'unité
systemd-analyze verify /etc/systemd/system/myapp.service

# Charger les modifications et redémarrer proprement
systemctl daemon-reload
systemctl restart myapp.service

# Examiner les journaux pour les refus et permissions manquantes
journalctl -u myapp.service -b

# Score de sécurité et indices
systemd-analyze security myapp.service

# Confirmer la configuration effective
systemctl show -p User,Group,NoNewPrivileges,CapabilityBoundingSet myapp.service

# Vérifier l'exposition réseau
ss -tulpn | grep 8080

Si un durcissement casse la fonctionnalité, revenez progressivement : commentez le dernier changement, lancez systemctl daemon-reload, redémarrez et retestez. N'ajoutez que les permissions ou appels système minimaux requis pour restaurer le comportement correct.

Plan pilote local

Objectif : appliquer une base durcie à un service non critique et vérifier le comportement localement avant un déploiement plus large.

Périmètre

  • Choisir un seul service avec des vérifications de santé claires (par exemple, un service HTTP interne sur localhost).

Plan

  1. Capturer le comportement actuel : quel utilisateur l'exécute, quels fichiers il écrit, quels ports il écoute, et les variables d'environnement nécessaires.
  2. Créer une surcharge drop-in plutôt que de modifier l'unité du fournisseur :
   systemctl edit myapp.service

Ajouter : User=, Group=, NoNewPrivileges=yes, ProtectSystem=strict, PrivateTmp=yes, CapabilityBoundingSet=, IPAddressDeny=any avec autorisation de la boucle locale.

  1. Ajouter StateDirectory=, LogsDirectory= et déplacer les écritures là-dedans ; supprimer les chemins d'écriture ad hoc.
  2. Ajouter RestrictAddressFamilies= et SystemCallFilter=@system-service ; redémarrer et vérifier les journaux pour les opérations refusées.
  3. Remplacer les secrets en ligne par LoadCredential= et pointer l'application vers $CREDENTIALS_DIRECTORY.
  4. Valider :
  • Lancer systemd-analyze security myapp.service et capturer le score avant/après.
  • Vérifications fonctionnelles : curl localhost:8080, vérifier les écritures de fichiers dans /var/lib/myapp, journaux dans /var/log/myapp.
  • ss -tulpn confirme seulement les écouteurs attendus.
  1. Plan de retour arrière : conserver chaque changement comme un commit et bloc de commentaires distincts. En cas d'échec, supprimer la dernière directive, lancer systemctl daemon-reload, redémarrer et retester.

Critères de sortie

  • Le service s'exécute de manière fiable lors des opérations normales.
  • Seuls les fichiers attendus sont accessibles en écriture.
  • Seuls les ports prévus sont accessibles.
  • Le score de sécurité s'améliore sans casser la fonctionnalité.

Conclusion

Les unités systemd durcies offrent des défenses fortes et reproductibles avec le moindre privilège, des permissions de système de fichiers explicites, des limites réseau strictes et une gestion sûre des secrets. Commencez par un petit pilote, mesurez les améliorations et itérez. Comme base durable, exécutez comme un utilisateur dédié, définissez NoNewPrivileges=yes, supprimez toutes les capacités, rendez le système de fichiers en lecture seule par défaut, autorisez seulement les chemins d'écriture requis, restreignez les familles d'adresses, appliquez IPAddressDeny/IPAddressAllow et utilisez les identifiants pour les secrets. Validez avec systemd-analyze verify et systemd-analyze security, observez le journal pour les refus, et étendez le motif à travers les services une fois stable.

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO