SELinux (Security-Enhanced Linux) est un système de contrôle d'accès obligatoire qui renforce considérablement la sécurité Linux. Ce guide explique comment maîtriser SELinux pour sécuriser vos serveurs.
Comprendre SELinux
Qu'est-ce que SELinux ?
SELinux = Security-Enhanced Linux, développé par NSA
Principe : Contrôle d'accès obligatoire (MAC - Mandatory Access Control) vs contrôle discrétionnaire standard (DAC).
Analogie :
- Sans SELinux : Si processus compromis run en tant que root → accès total système
- Avec SELinux : Même root limité par policies → damage containment
DAC vs MAC
DAC (Discretionary) - Linux standard :
# User possède fichier → contrôle accès
chmod 777 sensitive_file # User peut faire ça !
MAC (Mandatory) - SELinux :
# Policies système contrôlent accès
# User ne peut PAS bypasser même avec chmod
Pourquoi SELinux ?
Protection contre :
- Compromission processus
- Escalade privilèges
- Accès non autorisés
- Zero-day exploits
Use cases :
- Serveurs production
- Environnements régulés (PCI-DSS, HIPAA)
- Containers sécurisés
- Services exposés Internet
Modes SELinux
Trois Modes
Enforcing : Applique policies, bloque violations Permissive : Log violations, n'applique PAS Disabled : SELinux désactivé (déconseillé)
Vérifier Mode
# Mode actuel
getenforce
# Enforcing
# Status détaillé
sestatus
# SELinux status: enabled
# Current mode: enforcing
# Policy: targeted
Changer Mode
# Temporaire (jusqu'au reboot)
sudo setenforce 0 # Permissive
sudo setenforce 1 # Enforcing
# Permanent
sudo nano /etc/selinux/config
SELINUX=enforcing # enforcing, permissive, disabled
SELINUXTYPE=targeted # Policy type
# Reboot requis pour appliquer
sudo reboot
Workflow Recommandé
# 1. Développement/Test : Permissive
setenforce 0
# 2. Observer logs, créer policies
ausearch -m avc
# 3. Tester policies
# Créer custom policies...
# 4. Production : Enforcing
setenforce 1
Contexts SELinux
Structure Context
Format : user:role:type:level
Exemple : system_u:object_r:httpd_sys_content_t:s0
- User : SELinux user (system_u, unconfined_u)
- Role : Role (object_r, system_r)
- Type : Type/Domain (httpd_sys_content_t) ← Plus important
- Level : MLS level (s0, s0-s0:c0.c1023)
Voir Contexts
# Fichiers
ls -Z
# -rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 file.txt
# Processus
ps auxZ
# system_u:system_r:httpd_t:s0 apache
# Utilisateurs
id -Z
# unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Types Courants
# Web
httpd_t # Apache/Nginx process
httpd_sys_content_t # Web content (read-only)
httpd_sys_rw_content_t # Web content (read-write)
httpd_log_t # Web logs
# Database
mysqld_t # MySQL process
mysqld_db_t # MySQL data
# SSH
sshd_t # SSH daemon
ssh_home_t # .ssh directory
# General
user_home_t # User files
tmp_t # /tmp files
var_log_t # Logs
Gérer File Contexts
Voir Context Fichier
# Context actuel
ls -Z /var/www/html/index.html
# unconfined_u:object_r:httpd_sys_content_t:s0
# Récursif
ls -lZR /var/www/
Changer Context Temporaire
# chcon (change context) - temporaire
sudo chcon -t httpd_sys_content_t /var/www/html/newfile.html
# Récursif
sudo chcon -R -t httpd_sys_content_t /var/www/html/
# ATTENTION : Réinitialisé par restorecon !
Changer Context Permanent
# semanage - permanent
sudo semanage fcontext -a -t httpd_sys_content_t "/custom/www(/.*)?"
# Appliquer
sudo restorecon -Rv /custom/www
# Vérifier
ls -Z /custom/www
Restaurer Contexts Défaut
# Restaurer context par défaut
sudo restorecon -v /var/www/html/file.html
# Récursif
sudo restorecon -Rv /var/www/
# Forcer reset
sudo restorecon -F -Rv /var/www/
Policies SELinux
Types Policies
Targeted (défaut) : Protège services réseau Minimum : Protection minimale MLS : Multi-Level Security (très strict)
Voir Policies
# Policy actuelle
sestatus | grep Policy
# Policy: targeted
# Modules chargés
semodule -l
# Chercher policy
semodule -l | grep httpd
Booleans
Booleans = switches on/off features policies
# Lister booleans
getsebool -a
# Boolean spécifique
getsebool httpd_can_network_connect
# httpd_can_network_connect --> off
# Activer/désactiver
sudo setsebool httpd_can_network_connect on
# Permanent
sudo setsebool -P httpd_can_network_connect on
# Booleans utiles Apache/Nginx
httpd_can_network_connect # HTTP requests externes
httpd_can_network_connect_db # Connexion DB
httpd_can_sendmail # Envoyer emails
httpd_enable_cgi # Exécuter CGI
httpd_unified # Accès read/write
Troubleshooting SELinux
Identifier Violations
# Audit logs
sudo ausearch -m avc -ts recent
# Dernière heure
sudo ausearch -m avc -ts today
# Avec contexte
sudo ausearch -m avc -c httpd
# Grep logs
sudo grep -i denied /var/log/audit/audit.log
Exemple AVC Denial
type=AVC msg=audit(1706097600.123:456): avc: denied { read }
for pid=1234 comm="httpd" name="file.html" dev="sda1" ino=789012
scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:user_home_t:s0
tclass=file permissive=0
Analyse :
- Process : httpd (Apache)
- Action : read
- File : file.html
- Problem : httpd_t essaie lire user_home_t (pas autorisé)
- Solution : Changer context file.html vers httpd_sys_content_t
audit2allow
# Générer policy depuis logs
sudo ausearch -m avc -ts recent | audit2allow
# Avec explication
sudo ausearch -m avc -ts recent | audit2allow -w
# Générer module policy
sudo ausearch -m avc -ts recent | audit2allow -M myapp
# Charger module
sudo semodule -i myapp.pp
# ATTENTION : Vérifier policy avant charger !
# audit2allow génère permissif, potentiel sécurité
sealert (Interface Conviviale)
# Installer
sudo yum install setroubleshoot-server
# Analyser logs
sudo sealert -a /var/log/audit/audit.log
# Output suggest solutions :
# - Boolean à activer
# - Context à changer
# - Policy à créer
Cas Pratiques
Apache/Nginx Web Server
Problème : Site web /var/www/html/newsite ne charge pas
# 1. Vérifier context
ls -Z /var/www/html/newsite
# user_home_t ← MAUVAIS
# 2. Corriger context
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/html/newsite(/.*)?"
sudo restorecon -Rv /var/www/html/newsite
# 3. Si contenu doit être modifiable (CMS)
sudo chcon -R -t httpd_sys_rw_content_t /var/www/html/uploads/
# 4. Si Apache doit connecter DB
sudo setsebool -P httpd_can_network_connect_db on
# 5. Vérifier
sudo systemctl restart httpd
curl http://localhost/newsite
Custom Port Service
Problème : Apache port 8080 refusé
# Voir ports autorisés
sudo semanage port -l | grep http
# http_port_t: tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
# Ajouter port
sudo semanage port -a -t http_port_t -p tcp 8080
# Vérifier
sudo semanage port -l | grep 8080
# Restart service
sudo systemctl restart httpd
NFS Share
# Context NFS
sudo setsebool -P nfs_export_all_rw on
sudo setsebool -P nfs_export_all_ro on
# Context export directory
sudo semanage fcontext -a -t public_content_t "/nfs/share(/.*)?"
sudo restorecon -Rv /nfs/share
Docker/Podman
# SELinux + containers
sudo setsebool -P container_manage_cgroup on
# Volume mounts
docker run -v /host/data:/container/data:z image
# :z = private mount
# :Z = shared mount
# Voir container contexts
docker inspect container | grep -i label
Custom Policies
Créer Policy Module
Scénario : Application custom /opt/myapp
# 1. Mode permissive
sudo setenforce 0
# 2. Exécuter app, générer logs
/opt/myapp/bin/server
# 3. Analyser logs
sudo ausearch -m avc -ts recent | audit2allow -M myapp
# 4. Réviser policy générée
cat myapp.te
module myapp 1.0;
require {
type init_t;
type myapp_t;
class file { read write };
}
#============= myapp_t ==============
allow myapp_t init_t:file { read write };
# 5. Compiler et charger
sudo checkmodule -M -m -o myapp.mod myapp.te
sudo semodule_package -o myapp.pp -m myapp.mod
sudo semodule -i myapp.pp
# 6. Retour enforcing
sudo setenforce 1
Policy Types
# Créer file context
sudo semanage fcontext -a -t myapp_exec_t "/opt/myapp/bin(/.*)?"
sudo restorecon -Rv /opt/myapp
# Créer port
sudo semanage port -a -t myapp_port_t -p tcp 9000
# Boolean
sudo setsebool -P myapp_can_network on
Monitoring SELinux
Logs
# Audit logs principal
/var/log/audit/audit.log
# SELinux messages
/var/log/messages
# Tail temps réel
sudo tail -f /var/log/audit/audit.log | grep AVC
Statistiques
# Compter denials
sudo ausearch -m avc -ts today | grep denied | wc -l
# Top processus bloqués
sudo ausearch -m avc -ts today | grep comm | sort | uniq -c | sort -rn
Alerting
# Script monitoring
#!/bin/bash
# /usr/local/bin/selinux-monitor.sh
DENIALS=$(ausearch -m avc -ts recent | grep denied | wc -l)
if [ $DENIALS -gt 10 ]; then
echo "SELinux: $DENIALS denials detected!" | \
mail -s "SELinux Alert" admin@example.com
fi
# Cron
# */15 * * * * /usr/local/bin/selinux-monitor.sh
Hardening avec SELinux
Services Critiques
# SSH strict
sudo setsebool -P ssh_chroot_rw_homedirs off
# Web server minimal
sudo setsebool -P httpd_enable_homedirs off
sudo setsebool -P httpd_builtin_scripting off
# Database
sudo setsebool -P mysql_connect_any off
Confined Users
# Voir SELinux users
sudo semanage user -l
# Mapper Linux user → SELinux user
sudo semanage login -a -s user_u john
# Types users :
# unconfined_u - Pas de restrictions
# user_u - Restreint
# staff_u - Moins restreint (sudo)
# sysadm_u - Admin système
MCS (Multi-Category Security)
# Isoler processus même type
# Apache instance 1
chcon -l s0:c0 /var/www/site1
# Apache instance 2
chcon -l s0:c1 /var/www/site2
# site1 et site2 isolés même si même type httpd_t
SELinux + Systemd
Service File Context
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
[Service]
Type=simple
ExecStart=/opt/myapp/bin/server
SELinuxContext=system_u:system_r:myapp_t:s0
[Install]
WantedBy=multi-user.target
Socket Activation
# SELinux contexts sockets
sudo semanage port -a -t myapp_port_t -p tcp 9000
Troubleshooting Avancé
Mode Debug
# Activer messages détaillés
echo 1 > /sys/fs/selinux/checkreqprot
# Verbose audit
sudo auditctl -w /etc/shadow -p wa -k shadow-file
Tester Policy
# Simuler accès
sudo sesearch --allow -s httpd_t -t user_home_t -c file -p read
# Si vide = denied
# Si résultat = allowed
Exporter/Importer Policies
# Exporter
sudo semodule -e myapp
sudo semodule -E myapp.pp
# Importer autre serveur
sudo semodule -i myapp.pp
Migration vers SELinux
Activer sur Système Existant
# 1. Installer
sudo yum install selinux-policy selinux-policy-targeted
# 2. Config permissive
sudo nano /etc/selinux/config
SELINUX=permissive
# 3. Reboot
sudo reboot
# 4. Relabel filesystem (long !)
sudo touch /.autorelabel
sudo reboot
# 5. Observer logs 1 semaine
sudo ausearch -m avc -ts today
# 6. Créer policies nécessaires
# audit2allow...
# 7. Passer enforcing
sudo setenforce 1
sudo nano /etc/selinux/config
SELINUX=enforcing
# 8. Reboot final
sudo reboot
Relabel Filesystem
# Force relabel
sudo touch /.autorelabel
sudo reboot
# Ou manuel (système arrêté)
sudo fixfiles -F onboot
sudo reboot
Désactiver SELinux (Déconseillé)
Temporaire
sudo setenforce 0
Permanent (si vraiment nécessaire)
sudo nano /etc/selinux/config
SELINUX=disabled
sudo reboot
# ATTENTION : Faille sécurité !
# Utiliser permissive plutôt que disabled
Cheat Sheet
Commandes Essentielles
# Status
getenforce
sestatus
# Modes
setenforce 0/1
# Contexts
ls -Z
ps auxZ
chcon -t type file
restorecon -Rv /path
# Policies
semanage fcontext -a -t type "/path(/.*)?"
getsebool -a
setsebool -P boolean on
# Troubleshooting
ausearch -m avc -ts recent
audit2allow -w
sealert -a /var/log/audit/audit.log
# Ports
semanage port -a -t type -p tcp PORT
Bonnes Pratiques
Sécurité
□ Enforcing en production
□ Permissive seulement test/debug
□ Jamais disabled (sauf incompatibilité majeure)
□ Policies minimales (least privilege)
□ Audit logs monitoring
□ Relabel après modifications /
Workflow
# Développement
1. Permissive mode
2. Tester app
3. Analyser AVC denials
4. Créer policies
5. Tester policies
6. Enforcing mode
# Production
1. Enforcing always
2. Monitor logs
3. Alertes denials
4. Policies à jour
Documentation
# Documenter custom policies
# /etc/selinux/targeted/modules/active/modules/
# README.txt avec explication
# Commenter .te files
# "Allow myapp read config files"
Conclusion
SELinux renforce considérablement sécurité Linux :
Activer SELinux :
setenforce 1
sestatus
Modes :
- Enforcing : Production
- Permissive : Debug
- Disabled : Éviter
Contexts :
ls -Z # Voir
chcon -t type file # Temporaire
semanage fcontext # Permanent
restorecon # Restaurer
Troubleshooting :
ausearch -m avc # Logs
audit2allow # Générer policies
sealert -a # Analyse
Booleans :
getsebool -a
setsebool -P boolean on
Custom policies :
audit2allow -M myapp
semodule -i myapp.pp
Avec SELinux, même compromission processus reste contenue ! 🔒


