Sections du handbook

Contrôle d'accès obligatoire (SELinux / AppArmor)

Revu le

Le contrôle d'accès obligatoire confine chaque service au moindre privilège pour qu'un processus compromis ne puisse pas parcourir tout le système. Le seul état qui protège réellement est le mode enforcing.

La menace : en DAC, un root compromis tient toute la machine

Les permissions Linux classiques sont discrétionnaires (DAC) : le propriétaire d'un processus décide de ce à quoi il peut accéder, et un processus exécuté en tant que root peut accéder à tout. Dès qu'un attaquant prend le contrôle d'un démon exposé au réseau (un serveur web vulnérable, un parseur, une base mal configurée) il hérite de toute la portée de ce démon. Une seule faille d'exécution de code à distance devient un point d'appui pour lire /etc/shadow, écrire dans /root, charger un module noyau ou rebondir vers d'autres services. Rien dans le modèle DAC ne dit « le serveur web n'a aucune raison de lire les clés d'hôte SSH ». Le rayon d'impact d'une seule compromission, c'est toute la machine.

Pourquoi le durcir

Le contrôle d'accès obligatoire (MAC) inverse le modèle : c'est le noyau qui applique une politique à l'échelle du système, qu'aucun processus, pas même root, ne peut contourner. Chaque service confiné reçoit un profil (AppArmor) ou un domaine/type (SELinux) décrivant exactement quels fichiers, capacités, ports et opérations réseau il peut utiliser. Tout ce qui sort du profil est refusé et journalisé, indépendamment du propriétaire des fichiers. Une compromission totale devient un incident contenu : le serveur web piraté ne peut faire que ce qu'un serveur web a le droit de faire.

Le piège, c'est que le MAC ne protège que lorsqu'il est réellement en mode enforcing. SELinux a trois états (enforcing, permissive qui journalise mais autorise, et disabled), et les profils AppArmor sont en mode enforce ou complain. Une machine en permissive/complain, ou avec selinux=0 glissé dans la ligne de commande du noyau, paraît protégée mais ne bloque rien.

Ce que Pavois audite : l'état effectif résolu par le noyau

Pavois vérifie l'état effectif, résolu par le noyau du MAC, pas seulement le fait que des fichiers le mentionnent. Sur Debian/Ubuntu, il exécute aa-status pour confirmer que le module AppArmor est chargé, que des profils sont chargés et en mode enforce (pas silencieusement non confinés) ; il vérifie les paquets apparmor, apparmor-utils et libpam-apparmor. Sur RHEL, il confirme le runtime SELinux (libselinux, policycoreutils) et inspecte /proc/cmdline pour s'assurer que SELinux n'a pas été désactivé par selinux=0. Il protège la politique en vérifiant propriétaire/permissions de /etc/selinux, atteste la règle auditd qui enregistre les modifications de la politique MAC, et signale les utilitaires d'assouplissement (setroubleshoot, mcstrans) à retirer. Parce qu'il lit l'état résolu du noyau et des outils, une machine bloquée en permissive/complain est détectée là où un scan limité aux fichiers la déclarerait conforme.

Comment vérifier et opérer ?

SELinux :

  • Mode : getenforce (en vigueur), sestatus (statut complet + politique), setenforce 1 (temporaire), /etc/selinux/config (persistant SELINUX=enforcing).
  • Booléens : activer une option de politique sans écrire de règle : getsebool -a, puis setsebool -P httpd_can_network_connect on (le -P rend persistant). C'est ainsi qu'on accorde une permission légitime à un service confiné, pas en désactivant SELinux.
  • Contextes de fichiers : ce sont des étiquettes, pas des chemins : ls -Z les affiche ; un fichier au mauvais contexte est refusé. Corrigez avec restorecon -Rv <chemin> (réapplique les défauts de la politique) ou définissez une règle avec semanage fcontext -a -t <type> '<chemin>(/.*)?' puis restorecon.
  • Confiné vs non confiné : un service tournant en unconfined_service_t n'est pas protégé ; ps -eZ et sesearch révèlent les domaines qui ont échappé au confinement.

AppArmor : aa-status liste les profils chargés et leur mode ; aa-enforce /etc/apparmor.d/<profil> et aa-complain changent un profil ; les profils vivent dans /etc/apparmor.d/.

Corriger un refus proprement

Quand un service confiné casse, le mauvais correctif est setenforce 0. Le bon flux lit le refus AVC dans le journal d'audit et ajuste la politique :

ausearch -m avc -ts recent            # trouver le refus
audit2why < /var/log/audit/audit.log  # expliquer POURQUOI il a ete refuse
audit2allow -a -M monmodule           # generer un module de politique cible
semodule -i monmodule.pp              # le charger

Préférez un booléen s'il couvre le cas (setsebool -P), puis un relabel (restorecon), et seulement ensuite un module sur mesure. L'équivalent AppArmor est aa-logprof, qui parcourt le journal en mode complain et propose des mises à jour de profil.

Pièges

  • setenforce 0 n'est pas un correctif : il désactive la protection globalement pour masquer un seul refus. Utilisez un booléen, un relabel, ou audit2allow.
  • Désactiver puis réactiver SELinux force un relabel complet (touch /.autorelabel + redémarrage), parfois long ; préférez permissive à disabled si vous devez relâcher temporairement.
  • Le mode complain d'AppArmor journalise mais autorise : c'est pour le réglage, pas la protection. Confirmez enforce avec aa-status.
  • Un service en unconfined_service_t n'est pas protégé même avec SELinux enforcing ; vérifiez que vos démons exposés tournent dans un domaine confiné.

FAQ

Permissive ou enforcing ? Seuls enforcing (SELinux) et enforce (AppArmor) bloquent quoi que ce soit. Permissive/complain ne font que journaliser : ce sont des modes de réglage, pas du durcissement.

Mon application casse sous SELinux. Je le désactive ? Non. Lisez l'AVC (ausearch -m avc), expliquez-le (audit2why), puis corrigez par un booléen, un restorecon, ou un module audit2allow ciblé.

Pourquoi Pavois lit-il /proc/cmdline et aa-status plutôt que /etc/selinux/config ? Parce que selinux=0 sur la ligne noyau l'emporte sur le fichier de config, et qu'un profil peut être chargé mais non confiné. Seul le runtime résolu dit la vérité.