Aller au contenu

Sécurité et isolation

systemd offre de nombreuses fonctionnalités de sécurité pour isoler et restreindre les services. Cette section couvre le sandboxing, les capacités Linux, les namespaces et la limitation d'accès aux ressources.

Principe de moindre privilège

Chaque service devrait avoir uniquement les permissions nécessaires à son fonctionnement, rien de plus.

Configuration minimale sécurisée

[Service]
# Utilisateur dédié
User=myapp
Group=myapp
DynamicUser=yes

# Pas de nouveaux privilèges
NoNewPrivileges=yes

# Isolation basique
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes

# Chemins en lecture seule
ReadOnlyPaths=/
ReadWritePaths=/var/lib/myapp

Utilisateurs et groupes

Utilisateur statique

# Créer un utilisateur système
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/myapp myapp
[Service]
User=myapp
Group=myapp

Utilisateur dynamique

Création automatique d'un utilisateur éphémère :

[Service]
DynamicUser=yes
StateDirectory=myapp
CacheDirectory=myapp
LogsDirectory=myapp

Avantages :

  • Pas de pré-création nécessaire
  • UID/GID aléatoires
  • Nettoyage automatique
  • Sécurité renforcée

Groupes supplémentaires

[Service]
User=myapp
Group=myapp
SupplementaryGroups=ssl-cert docker

Isolation du système de fichiers

ProtectSystem

Contrôle l'accès en écriture au système :

[Service]
# Niveau de protection
ProtectSystem=no       # Aucune protection
ProtectSystem=yes      # /usr et /boot en lecture seule
ProtectSystem=full     # + /etc en lecture seule
ProtectSystem=strict   # Tout en lecture seule

strict est le plus sécurisé. Nécessite de définir explicitement les chemins écritables.

ProtectHome

Restreint l'accès aux répertoires home :

[Service]
ProtectHome=no         # Accès complet
ProtectHome=yes        # /home, /root, /run/user inaccessibles
ProtectHome=read-only  # Accès en lecture seule
ProtectHome=tmpfs      # Monté en tmpfs vide

PrivateTmp

Isole /tmp et /var/tmp :

[Service]
PrivateTmp=yes

Crée un namespace /tmp unique pour le service.

ReadOnlyPaths / ReadWritePaths

Contrôle fin des accès :

[Service]
# Tout en lecture seule
ReadOnlyPaths=/

# Sauf ces chemins
ReadWritePaths=/var/lib/myapp
ReadWritePaths=/var/log/myapp
ReadWritePaths=/run/myapp

InaccessiblePaths

Rend des chemins complètement inaccessibles :

[Service]
InaccessiblePaths=/home
InaccessiblePaths=/root
InaccessiblePaths=/proc/kcore

TemporaryFileSystem

Monte un tmpfs à un emplacement :

[Service]
TemporaryFileSystem=/var:ro
BindReadOnlyPaths=/var/lib/myapp

Répertoires gérés

systemd peut créer et gérer automatiquement des répertoires :

[Service]
# Création automatique avec bonnes permissions
StateDirectory=myapp              # /var/lib/myapp
CacheDirectory=myapp              # /var/cache/myapp
LogsDirectory=myapp               # /var/log/myapp
ConfigurationDirectory=myapp     # /etc/myapp
RuntimeDirectory=myapp            # /run/myapp

# Permissions
StateDirectoryMode=0750
CacheDirectoryMode=0750

# Nettoyage automatique
RuntimeDirectoryPreserve=no      # Supprimé à l'arrêt

Isolation réseau

PrivateNetwork

Isole complètement du réseau :

[Service]
PrivateNetwork=yes

Le service n'a accès qu'à l'interface loopback.

RestrictAddressFamilies

Limite les types de sockets :

[Service]
# Autoriser seulement IPv4 et IPv6
RestrictAddressFamilies=AF_INET AF_INET6

# Autoriser seulement Unix sockets
RestrictAddressFamilies=AF_UNIX

# Bloquer tout
RestrictAddressFamilies=none

IPAddressAllow / IPAddressDeny

Filterage par IP (nécessite cgroups v2) :

[Service]
# Autoriser seulement certaines IPs
IPAddressAllow=10.0.0.0/8 192.168.1.0/24
IPAddressDeny=any

# Ou bloquer certaines IPs
IPAddressDeny=192.168.1.100

Capacités Linux

Les capacités décomposent les privilèges root en permissions granulaires.

Supprimer toutes les capacités

[Service]
CapabilityBoundingSet=
AmbientCapabilities=

Autoriser des capacités spécifiques

[Service]
# Bind sur ports < 1024
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE

Capacités courantes

  • CAP_NET_BIND_SERVICE : Bind ports < 1024
  • CAP_NET_RAW : Sockets raw (ping)
  • CAP_NET_ADMIN : Configuration réseau
  • CAP_SYS_ADMIN : Opérations système (mount, etc.)
  • CAP_SYS_TIME : Modifier l'horloge système
  • CAP_DAC_OVERRIDE : Outrepasser permissions fichiers
  • CAP_CHOWN : Changer propriétaire fichiers

Exemple : serveur web

[Service]
User=www-data
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes

Permet de binder sur le port 80/443 sans être root.

Systèmes d'appel (seccomp)

Bloquer les syscalls dangereux avec seccomp :

Profils prédéfinis

[Service]
# Bloquer tous sauf liste blanche
SystemCallFilter=@system-service

# Bloquer syscalls dangereux
SystemCallFilter=~@privileged @resources @obsolete

Groupes de syscalls

Exemple : service web sécurisé

[Service]
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources @obsolete @debug
SystemCallErrorNumber=EPERM

Bloquer des syscalls spécifiques

[Service]
SystemCallFilter=~ptrace personality

Limitations diverses

NoNewPrivileges

Empêche l'obtention de nouveaux privilèges :

[Service]
NoNewPrivileges=yes

Bloquer setuid, setgid, file capabilities.

ProtectKernelTunables

Protège /proc/sys, /sys en lecture seule :

[Service]
ProtectKernelTunables=yes

ProtectKernelModules

Empêche le chargement de modules noyau :

[Service]
ProtectKernelModules=yes

ProtectControlGroups

Protège la hiérarchie cgroups :

[Service]
ProtectControlGroups=yes

ProtectKernelLogs

Bloquer l'accès aux logs noyau :

[Service]
ProtectKernelLogs=yes

ProtectHostname

Empêche la modification du hostname :

[Service]
ProtectHostname=yes

ProtectClock

Empêche la modification de l'horloge :

[Service]
ProtectClock=yes

ProtectProc

Masque les informations /proc :

[Service]
ProtectProc=invisible    # Masquer les autres processus
ProtectProc=noaccess    # Bloquer accès /proc

ProcSubset

Limiter le contenu de /proc :

[Service]
ProcSubset=pid    # Seulement /proc/PID

PrivateDevices

Isole /dev :

[Service]
PrivateDevices=yes

Accès seulement à /dev/null, /dev/zero, /dev/urandom.

PrivateUsers

Namespace utilisateur :

[Service]
PrivateUsers=yes

Map UID/GID du service vers des IDs non-privilégiés.

PrivateIPC

Isole IPC (shared memory, semaphores) :

[Service]
PrivateIPC=yes

Restriction d'exécution

LockPersonality

Empêche changement de personnalité :

[Service]
LockPersonality=yes

MemoryDenyWriteExecute

Bloquer W^X (write XOR execute) :

[Service]
MemoryDenyWriteExecute=yes

Empêche les pages mémoire à la fois écritables et exécutables.

RestrictRealtime

Bloquer le scheduling temps réel :

[Service]
RestrictRealtime=yes

RestrictSUIDSGID

Bloquer création fichiers SUID/SGID :

[Service]
RestrictSUIDSGID=yes

RestrictNamespaces

Limiter création de namespaces :

[Service]
RestrictNamespaces=yes

# Ou autoriser certains types
RestrictNamespaces=uts ipc

Exemple : Service ultra-sécurisé

[Unit]
Description=Highly Secured Service

[Service]
# Utilisateur
DynamicUser=yes
User=myapp

# Pas de privilèges
NoNewPrivileges=yes
CapabilityBoundingSet=
AmbientCapabilities=

# Isolation système de fichiers
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadOnlyPaths=/
ReadWritePaths=/var/lib/myapp
InaccessiblePaths=/home /root

# Répertoires gérés
StateDirectory=myapp
CacheDirectory=myapp
LogsDirectory=myapp
StateDirectoryMode=0700

# Isolation réseau
PrivateNetwork=yes
RestrictAddressFamilies=AF_UNIX

# Protection noyau
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectHostname=yes
ProtectClock=yes

# Isolation proc et devices
ProtectProc=invisible
ProcSubset=pid
PrivateDevices=yes
PrivateUsers=yes
PrivateIPC=yes

# Restrictions exécution
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes

# Seccomp
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources @obsolete @debug
SystemCallErrorNumber=EPERM

# Limites ressources
MemoryMax=512M
TasksMax=100

[Install]
WantedBy=multi-user.target

Audit de sécurité

Analyser la sécurité d'un service

# Score de sécurité (systemd >= 248)
systemd-analyze security myapp.service

# Détails
systemd-analyze security --no-pager myapp.service

# Seulement les warnings
systemd-analyze security myapp.service | grep -E 'WARN|UNSAFE'

Vérifier les capacités

# Capacités d'un service
systemctl show myapp.service -p CapabilityBoundingSet
systemctl show myapp.service -p AmbientCapabilities

Vérifier les protections actives

systemctl show myapp.service | grep -E '(Protect|Private|Restrict)'

Bonnes pratiques

  1. Toujours utiliser NoNewPrivileges
NoNewPrivileges=yes
  1. Privilèges minimaux
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
  1. Isolation maximale
ProtectSystem=strict
PrivateTmp=yes
PrivateDevices=yes
  1. Utilisateurs dédiés
DynamicUser=yes
  1. Bloquer syscalls dangereux
SystemCallFilter=@system-service
  1. Auditer régulièrement
systemd-analyze security
  1. Tester après changements
systemctl restart myapp
journalctl -u myapp -f

La sécurité systemd permet de créer des services robustes et isolés, réduisant considérablement la surface d'attaque.