SELinux en 2026 : guide complet pour durcir RHEL 10, Fedora 42 et Rocky Linux

Guide SELinux 2026 pour RHEL 10, Fedora 42 et Rocky Linux : activer enforcing, écrire des politiques avec audit2allow, dépanner les AVC et confiner Podman.

SELinux 2026 : Guide RHEL 10 & Fedora 42

Mis à jour : 13 juin 2026

SELinux (Security-Enhanced Linux) est un module de sécurité du noyau (LSM) qui impose un contrôle d'accès obligatoire (MAC) entre chaque processus, fichier, port et IPC d'un système Linux. En 2026, SELinux reste activé en mode enforcing par défaut sur RHEL 10, Fedora 42 et Rocky Linux 10, et son écosystème (semanage, audit2allow, setroubleshoot, container-selinux) le rend bien plus pragmatique que sa réputation ne le laisse croire. Ce guide explique, étape par étape, comment l'activer, écrire des politiques, dépanner les blocages et l'intégrer aux conteneurs.

  • SELinux applique le MAC à travers le hook LSM du noyau Linux 6.12+. Depuis Linux 5.7, le hook supporte l'empilement (LSM stacking) avec BPF LSM.
  • RHEL 10, Fedora 42 et Rocky Linux 10 livrent SELinux activé en enforcing avec la politique targeted (paquet selinux-policy ≥ 40.x).
  • Honnêtement, 90 % des problèmes utilisateurs se règlent avec trois commandes : ausearch -m AVC, audit2allow et semanage fcontext. Pas besoin de désactiver SELinux.
  • Les booléens (getsebool / setsebool) permettent d'ajuster une politique sans la recompiler, contrairement à AppArmor qui exige une réédition des profils.
  • SELinux protège Podman et Docker via container-selinux en confinant chaque conteneur dans un contexte MCS unique (catégories c0,c1 à c1023).
  • Désactiver SELinux pour « régler un problème » est presque toujours la mauvaise décision. La politique est correcte, c'est l'étiquetage qui est faux dans 95 % des cas.

SELinux en 2026 : qu'est-ce qui a changé ?

SELinux a vingt-trois ans cette année, et la version 2026 du framework est très différente de celle qu'on connaissait sous RHEL 5. Voici les changements récents qui comptent vraiment, du point de vue d'un ingénieur kernel :

  • Linux 6.12 LTS (novembre 2024) a stabilisé la pile LSM (LSM stacking). SELinux peut désormais cohabiter avec BPF LSM sur le même hook, ce qui permet d'ajouter des contrôles eBPF sans désactiver SELinux. C'est la première fois qu'on peut empiler du runtime telemetry au-dessus du MAC traditionnel.
  • RHEL 10 (mai 2025) et Rocky Linux 10 (juin 2025) embarquent selinux-policy-40.x avec une politique targeted retravaillée pour systemd 257, cgroup v2 et Wayland.
  • Fedora 42 (avril 2025) livre policycoreutils-3.7 et migre toute la politique vers CIL (Common Intermediate Language), abandonnant définitivement la chaîne m4 de la Reference Policy pour les nouveaux modules.
  • CVE-2024-1086 (élévation de privilèges via nf_tables, CVSS 7.8) a rappelé qu'une politique SELinux targeted bien étiquetée limite massivement la surface d'exploitation post-LPE. Un attaquant qui obtient uid=0 reste piégé dans son domaine unconfined_t ou son contexte de service. La fiche NVD officielle de cette CVE détaille la chaîne d'exploitation et ses mitigations.
  • Le paquet container-selinux 2.234+ ajoute le support natif pour Podman 5.x avec étiquetage automatique MCS sur les volumes :Z et :z.

SELinux vs AppArmor : quel MAC choisir ?

La question revient à chaque audit : faut-il SELinux ou AppArmor ? Les deux sont des modules LSM, les deux font du contrôle d'accès obligatoire, mais ils opèrent à des niveaux de granularité très différents. Le tableau ci-dessous résume les dimensions qui pèsent réellement dans la décision.

CritèreSELinuxAppArmor
ModèleÉtiquetage (type enforcement) sur chaque inodeChemin (path-based) sur le système de fichiers
GranularitéTrès fine : processus, fichier, port, IPC, capability, signalFine : fichiers, capabilities, sockets réseau
Distributions par défautRHEL, Fedora, Rocky, AlmaLinux, CentOS StreamUbuntu, Debian, openSUSE, SUSE Linux Enterprise
Courbe d'apprentissageRaide (contextes, types, booléens, MCS)Douce (profils lisibles en texte)
Outils de dépannageausearch, sealert, audit2allowaa-logprof, aa-genprof, aa-status
Conformité réglementaireFIPS 140-3, Common Criteria EAL4+, CIS, STIG, ANSSICIS, partiellement STIG
Conteneurs (Podman/Docker)Étiquetage MCS automatique par conteneurProfil docker-default global
PerformanceSurcoût ~1-3 % en workload mixteSurcoût ~1-2 %

En pratique, le choix se fait par la distribution. Si vous gérez du RHEL/Rocky/Fedora, restez sur SELinux : la politique targeted est maintenue par Red Hat et couvre des milliers de services. Si vous gérez de l'Ubuntu/Debian, AppArmor est l'option par défaut et l'outillage aa-* est mieux intégré. Pour un comparatif détaillé du côté AppArmor, consultez notre guide AppArmor 2026. Tenter de faire tourner les deux sur la même machine n'est pas supporté : un seul LSM « majeur » à la fois, mais vous pouvez empiler BPF LSM par-dessus depuis le kernel 5.7.

Comment activer SELinux en mode enforcing ?

Sur RHEL 10, Fedora 42 ou Rocky Linux 10, SELinux est déjà en enforcing à l'installation. La vraie question pratique est donc : comment vérifier l'état, comment le réactiver après qu'un administrateur l'ait désactivé « pour tester », et comment passer d'un mode à l'autre sans casser le système ?

Vérifiez d'abord l'état courant :

# État runtime + état au démarrage + politique chargée
sestatus

# Sortie attendue :
# SELinux status:                 enabled
# SELinuxfs mount:                /sys/fs/selinux
# SELinux root directory:         /etc/selinux
# Loaded policy name:             targeted
# Current mode:                   enforcing
# Mode from config file:          enforcing
# Policy MLS status:              enabled
# Policy deny_unknown status:     allowed
# Memory protection checking:     actual (secure)
# Max kernel policy version:      33

Pour basculer temporairement entre enforcing (1) et permissive (0) :

# Passer en permissive (les violations sont loggées mais pas bloquées)
sudo setenforce 0

# Repasser en enforcing
sudo setenforce 1

# Vérifier le mode courant uniquement
getenforce

Pour persister le changement au redémarrage, éditez /etc/selinux/config :

# /etc/selinux/config
# SELINUX peut prendre les valeurs : enforcing, permissive, disabled
SELINUX=enforcing
# SELINUXTYPE : targeted (par défaut), mls, minimum
SELINUXTYPE=targeted

Si vous gérez un parc, la configuration noyau via le paramètre selinux=0 dans /etc/default/grub doit aussi être retirée. C'est l'oubli classique qui fait que SELinux reste désactivé même après avoir corrigé /etc/selinux/config.

Comprendre les contextes de sécurité (utilisateur, rôle, type, MCS)

Tout, sous SELinux, porte une étiquette appelée contexte de sécurité. Cette étiquette est stockée dans l'attribut étendu security.selinux de l'inode pour les fichiers, et dans la structure task_struct du noyau pour les processus. Le format est le suivant :

utilisateur_u:rôle_r:type_t:niveau_MCS
# Exemple sur un fichier :
# system_u:object_r:httpd_sys_content_t:s0

Les quatre champs jouent des rôles distincts :

  • Utilisateur SELinux (system_u, unconfined_u, user_u) : différent de l'UID POSIX, c'est un mapping géré par semanage login.
  • Rôle (object_r pour les fichiers, system_r, unconfined_r pour les processus) : utilisé par le modèle RBAC.
  • Type (le type enforcement, l'essentiel) : httpd_t, sshd_t, container_t. La politique définit ce que chaque type peut faire à chaque autre type.
  • Niveau MCS/MLS (s0, s0:c0.c1023) : multi-catégorie ou multi-niveau, utilisé pour isoler les conteneurs et les workloads classifiés.

Pour inspecter les contextes :

# Contexte d'un fichier
ls -Z /var/www/html/index.html
# unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html

# Contexte d'un processus
ps -eZ | grep nginx
# system_u:system_r:httpd_t:s0  1234 ?  Ssl  0:00 nginx: master

# Contexte d'un port
sudo semanage port -l | grep http
# http_port_t  tcp  80, 81, 443, 488, 8008, 8009, 8443, 9000

La règle de base à retenir : SELinux ne se trompe presque jamais sur la politique, mais souvent sur l'étiquetage. Si Apache ne sert pas un fichier, c'est généralement parce que le fichier porte le type user_home_t au lieu de httpd_sys_content_t. La solution n'est pas d'ouvrir la politique, c'est de corriger l'étiquette.

Gérer les booléens, ports et étiquettes avec semanage

Plutôt que de réécrire la politique, SELinux expose des booléens qui activent ou désactivent des règles préfabriquées. Sur RHEL 10, il y en a plus de 300, couvrant la quasi-totalité des cas de configuration courants. C'est le bon premier réflexe avant d'écrire du code de politique.

# Lister les booléens liés à httpd
getsebool -a | grep httpd
# httpd_can_network_connect --> off
# httpd_can_network_connect_db --> off
# httpd_enable_homedirs --> off
# httpd_use_nfs --> off
# ...

# Activer un booléen de manière persistante (-P écrit dans la politique)
sudo setsebool -P httpd_can_network_connect on

# Vérifier qu'il est actif au prochain redémarrage
getsebool httpd_can_network_connect
# httpd_can_network_connect --> on

Pour autoriser un service à écouter sur un port non standard, n'éditez pas la politique. Ajoutez simplement le port au bon type. Exemple : faire écouter sshd sur le port 2222.

# Ajouter le port 2222/tcp au type ssh_port_t
sudo semanage port -a -t ssh_port_t -p tcp 2222

# Vérifier
sudo semanage port -l | grep ssh
# ssh_port_t  tcp  2222, 22

Pour corriger l'étiquette d'un répertoire personnalisé (par exemple servir du web depuis /srv/sites) :

# Déclarer la règle d'étiquetage dans la politique (persistante)
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/sites(/.*)?"

# Appliquer immédiatement l'étiquette aux fichiers existants
sudo restorecon -Rv /srv/sites

La paire semanage fcontext + restorecon est la combinaison qu'il faut mémoriser : la première inscrit la règle, la seconde l'applique. Utiliser chcon à la place fonctionne, mais l'étiquette sera réécrasée au prochain restorecon ou relabel. chcon n'est utile que pour tester rapidement.

Écrire une politique SELinux personnalisée avec audit2allow

Quand un service refuse une opération que ni les booléens ni l'étiquetage ne couvrent (typiquement un démon maison ou un binaire propriétaire), il faut écrire un module de politique. audit2allow automatise 90 % du travail à partir des journaux d'audit.

Voici la méthode standard, étape par étape :

# 1. Passez le service en permissive uniquement (sans toucher au reste)
sudo semanage permissive -a myapp_t   # si le domaine existe déjà
# ou pour un binaire non confiné, lancez-le et collectez les AVC

# 2. Reproduisez le scénario complet du service (démarrage, requêtes, arrêt)
sudo systemctl restart myapp
curl http://localhost:8080/healthcheck

# 3. Extrayez les AVC depuis le journal d'audit
sudo ausearch -m AVC,USER_AVC -ts recent

# 4. Générez un module de politique candidat
sudo ausearch -m AVC,USER_AVC -ts recent | audit2allow -M myapp_local

# Cela produit :
#   myapp_local.te  (source Type Enforcement, à relire absolument)
#   myapp_local.pp  (paquet binaire prêt à charger)

# 5. RELISEZ le .te avant de l'installer. C'est l'étape critique.
cat myapp_local.te

Un fichier .te généré ressemble à ceci :

module myapp_local 1.0;

require {
    type myapp_t;
    type var_log_t;
    type http_port_t;
    class file { open read write };
    class tcp_socket name_connect;
}

#============= myapp_t ==============
allow myapp_t var_log_t:file { open read write };
allow myapp_t http_port_t:tcp_socket name_connect;

Une fois la politique relue et nettoyée, installez-la :

# Charger le module
sudo semodule -i myapp_local.pp

# Lister les modules chargés
sudo semodule -l | grep myapp
# myapp_local

# Retirer le module si besoin
sudo semodule -r myapp_local

# Et bien sûr, ne pas oublier de retirer la permissive
sudo semanage permissive -d myapp_t

Pour les politiques plus complexes, écrire directement en CIL (Common Intermediate Language) devient l'approche recommandée depuis Fedora 38. Le format .cil est le langage natif que secilc compile, sans passer par les macros m4 de la Reference Policy. Le projet SELinux Notebook officiel contient un chapitre dédié à CIL qui reste la meilleure référence en 2026.

Comment dépanner SELinux quand une application est bloquée ?

La procédure de dépannage SELinux tient en cinq étapes, dans cet ordre, et résout la grande majorité des cas sans jamais désactiver le MAC.

  1. Confirmer que SELinux est bien la cause. Mettez le système en permissive avec setenforce 0 et reproduisez. Si le problème persiste, ce n'est pas SELinux ; repassez en enforcing et cherchez ailleurs (firewall, droits POSIX, systemd).
  2. Lire les AVC déniés. Les refus apparaissent comme Access Vector Cache (AVC) dans le journal d'audit. Utilisez ausearch avec un filtre temporel :
    sudo ausearch -m AVC,USER_AVC,SELINUX_ERR -ts recent
    # ou pour les dernières 10 minutes :
    sudo ausearch -m AVC -ts -10minutes
    
  3. Demander une explication lisible. Le démon setroubleshootd (paquet setroubleshoot-server) traduit chaque AVC en français/anglais avec une suggestion :
    sudo sealert -a /var/log/audit/audit.log
    # Sortie : "SELinux is preventing httpd from read access on the file index.html.
    #          If you want to allow httpd to read this file...
    #          Then you need to change the label on /var/www/site/index.html
    #          # semanage fcontext -a -t httpd_sys_content_t '/var/www/site(/.*)?'"
    
  4. Comprendre pourquoi avec audit2why. Pour les cas où sealert ne donne pas de suggestion, audit2why indique si c'est un booléen, une dontaudit cachée, ou une vraie règle manquante :
    sudo ausearch -m AVC -ts recent | audit2why
    
  5. Appliquer le moindre correctif possible. Dans l'ordre de préférence : (a) corriger l'étiquette avec semanage fcontext + restorecon, (b) activer un booléen avec setsebool -P, (c) ajouter un port avec semanage port, (d) en dernier recours, écrire un module avec audit2allow.

SELinux et conteneurs : container-selinux, Podman et Docker

Sur RHEL/Fedora/Rocky, Podman et Docker s'appuient sur le paquet container-selinux (≥ 2.234 en 2026) qui définit les types container_t, container_file_t et container_runtime_t. Chaque conteneur lancé reçoit automatiquement une étiquette MCS unique de la forme s0:c247,c873, ce qui empêche un conteneur compromis de lire les fichiers d'un autre conteneur, même s'ils tournent tous deux en uid=0.

Petite démonstration :

# Lancer deux conteneurs et observer leurs étiquettes
podman run -d --name a alpine sleep 1000
podman run -d --name b alpine sleep 1000

ps -eZ | grep sleep
# system_u:system_r:container_t:s0:c247,c873  12345 sleep 1000
# system_u:system_r:container_t:s0:c104,c512  12346 sleep 1000

# Les catégories MCS diffèrent : a ne peut pas accéder aux fichiers de b

Pour monter un volume host accessible au conteneur, deux options d'étiquetage s'offrent à vous :

# :Z = étiquetage privé au conteneur (un seul conteneur peut accéder)
podman run -v /srv/data:/data:Z alpine ls /data

# :z = étiquetage partagé (plusieurs conteneurs peuvent partager le volume)
podman run -v /srv/shared:/data:z alpine ls /data

Pour un déploiement Kubernetes ou Podman en production, combinez SELinux avec un outil de détection runtime comme Falco ou Tetragon. Le confinement MAC bloque ce qui ne devrait pas se produire, et la télémétrie eBPF observe ce qui se produit malgré tout. Notre guide pratique de la sécurité runtime des conteneurs avec eBPF détaille cette combinaison.

Bonnes pratiques de durcissement avec SELinux

Un déploiement SELinux solide en 2026 repose sur une dizaine de pratiques que j'applique systématiquement sur les serveurs que je durcis. Elles sortent toutes du cadre « SELinux activé » et abordent la défense en profondeur.

  1. Restez en enforcing, jamais en permissive en production. permissive est un mode de débogage, pas un mode d'exploitation. Un système en permissive donne une fausse impression de sécurité (les outils de conformité voient SELinux « actif »).
  2. Auditez la politique unconfined_t. Les processus dans unconfined_t ne sont pas réellement confinés. Visez à confiner tout service exposé au réseau : si un service tourne en unconfined_service_t, écrivez un module pour lui donner son propre type.
  3. Désactivez les booléens dangereux par défaut. Par exemple httpd_can_network_connect est off à dessein. Ne l'activez que si votre application le requiert vraiment, et documentez pourquoi dans votre playbook Ansible.
  4. Synchronisez votre politique avec votre configuration réseau. Si vous changez le port SSH dans sshd_config, ajoutez le port à ssh_port_t ET ouvrez-le dans nftables. Voir notre guide complet nftables 2026 pour le côté pare-feu.
  5. Versionnez vos modules .cil et .te en Git. Traitez la politique SELinux comme du code : revues de PR, tests sur une VM permissive avant promotion en enforcing, intégration aux pipelines CI/CD.
  6. Surveillez les violations en continu. Envoyez les événements AVC vers votre SIEM (Wazuh, Loki) avec une règle d'alerte sur les pics de refus. Ils signalent souvent une compromission ou une nouvelle version d'application mal étiquetée.
  7. Auditez avec un scanner de conformité. OpenSCAP (oscap) et Lynis vérifient que SELinux est conforme aux benchmarks CIS, STIG ou ANSSI. La documentation officielle « Using SELinux » de Red Hat pour RHEL 10 liste les contrôles applicables.
  8. Empilez BPF LSM par-dessus. Sur kernel ≥ 6.6, activez BPF LSM avec lsm=selinux,bpf dans la ligne de commande du noyau pour ajouter des contrôles eBPF spécifiques (par exemple, restreindre bpf() aux processus avec une étiquette donnée).
  9. Mettez à jour selinux-policy à chaque cycle de patch. Les politiques évoluent avec les nouvelles versions des services confinés (nginx, postgresql, kubelet). Une politique obsolète génère des refus inutiles et des contournements.
  10. Pour les conteneurs, gardez container-selinux à jour. Le paquet livre les types nécessaires aux nouveaux runtimes (containerd 2.0, CRI-O 1.30, Podman 5.x). La documentation Fedora SELinux Getting Started reste le tutoriel le plus à jour pour les versions récentes.

Foire aux questions

Comment désactiver SELinux temporairement sans redémarrer ?

Lancez sudo setenforce 0 pour passer en mode permissive. Les règles ne sont plus appliquées mais les violations restent loggées dans /var/log/audit/audit.log, ce qui vous permet de diagnostiquer. Restaurez avec sudo setenforce 1. Ne modifiez pas /etc/selinux/config sauf si vous voulez que le changement survive au redémarrage.

Quelle est la différence entre enforcing, permissive et disabled ?

Enforcing applique la politique et bloque les opérations refusées. Permissive évalue la politique et journalise les refus mais ne bloque rien, ce qui est utile pour le débogage. Disabled arrête complètement le sous-système SELinux et désactive l'étiquetage des nouveaux fichiers ; à éviter en production car le retour en arrière exige un ré-étiquetage complet du système de fichiers.

SELinux ralentit-il les performances d'un serveur Linux ?

Le surcoût mesuré est de l'ordre de 1 à 3 % sur un workload mixte web/base de données, et inférieur à 1 % sur du calcul pur. Le coût est dominé par les vérifications AVC lors des opérations système (open, exec, connect) ; sur les workloads I/O-intensifs, le cache AVC absorbe l'essentiel et la surcharge devient négligeable.

Comment savoir quel type SELinux assigner à un nouveau répertoire ?

Cherchez un répertoire équivalent existant et copiez son type. Par exemple, pour du contenu web : matchpathcon /var/www/html renvoie httpd_sys_content_t. Appliquez-le à votre nouveau chemin avec semanage fcontext -a -t httpd_sys_content_t "/srv/sites(/.*)?" puis restorecon -Rv /srv/sites.

Puis-je faire tourner SELinux et AppArmor en même temps ?

Non, un seul LSM « majeur » peut être actif à la fois sur un noyau Linux. En revanche, depuis le kernel 5.7, l'empilement LSM permet d'utiliser SELinux (ou AppArmor) avec d'autres modules « mineurs » comme BPF LSM, Yama, Landlock ou Lockdown. C'est cette combinaison qui devient la norme en 2026 : SELinux pour le MAC, BPF LSM pour les contrôles dynamiques.

Pourquoi mon service échoue alors que SELinux est en permissive ?

Si le service échoue toujours en permissive, le problème n'est pas SELinux. Cherchez du côté des droits POSIX (ls -l), du pare-feu (nft list ruleset), de systemd (systemctl status, journalctl -u) ou des capabilities. SELinux en permissive n'interdit rien, il n'est que rarement coupable des dépannages « par défaut ».

Yuki Tanaka
À propos de l'auteur Yuki Tanaka

Linux kernel security engineer with a background in eBPF and LSM. Likes hardening more than she likes sleeping.