💡 Vous arrivez directement à ce lab sans avoir fait les précédents ? Chaque lab de ce dépôt est autonome. Pré-requis unique : les 4 VMs du lab doivent répondre au ping Ansible.
cd /home/bob/Projets/ansible-training ansible all -m ansible.builtin.ping # → 4 "pong" attendusSi KO, lancez
make bootstrap && make provisionà la racine du repo (cf. README racine pour les détails).
SELinux (Security-Enhanced Linux) est le système de contrôle d'accès
obligatoire activé par défaut sur RHEL/AlmaLinux/Rocky en mode enforcing.
Trois modules Ansible le gèrent :
ansible.posix.selinux:— état global (enforcing / permissive / disabled)- politique active.
ansible.posix.seboolean:— activer/désactiver des booléens SELinux (httpd_can_network_connect, etc.).community.general.sefcontext:— gérer les contextes des fichiers (avecrestoreconpour appliquer).
Ces modules sont dans ansible.posix et community.general —
ansible-galaxy collection install ansible.posix community.general.
À la fin de ce lab, vous saurez :
- Vérifier l'état SELinux et le mode (enforcing / permissive).
- Modifier un booléen SELinux avec persistance.
- Définir un contexte custom sur un dossier (
sefcontext+restorecon). - Comprendre pourquoi un reboot peut être nécessaire (changement de mode).
- Diagnostiquer un service qui plante "à cause de SELinux".
cd /home/bob/Projets/ansible-training
ansible-galaxy collection install ansible.posix community.general
ansible db1.lab -m ping
# Installer les outils Python SELinux (necessaires aux modules)
ansible db1.lab -b -m dnf -a "name=python3-libselinux,policycoreutils-python-utils state=present"
ansible db1.lab -b -m shell -a "rm -rf /var/www/myapp; mkdir -p /var/www/myapp"---
- name: Demo selinux state
hosts: db1.lab
become: true
tasks:
- name: Verifier l etat SELinux courant
ansible.builtin.command: getenforce
register: enforce
changed_when: false
- name: Afficher
ansible.builtin.debug:
msg: |
Mode SELinux : {{ enforce.stdout }}
ansible_selinux : {{ ansible_selinux.status | default('unknown') }}
policy : {{ ansible_selinux.type | default('unknown') }}🔍 Observation : Enforcing sur AlmaLinux par défaut. Les facts
ansible_selinux.* sont collectés automatiquement (gather_facts: true).
3 modes possibles :
| Mode | Effet |
|---|---|
enforcing |
Contraintes appliquées + violations bloquées (production RHEL) |
permissive |
Violations loguées mais pas bloquées (debug) |
disabled |
SELinux complètement désactivé (à éviter en prod) |
- name: Passer en permissive (debug temporaire)
ansible.posix.selinux:
policy: targeted
state: permissive🔍 Observation : le module modifie /etc/selinux/config (effet après
reboot) ET applique le mode maintenant (setenforce 0).
Désactiver complètement (à éviter sauf cas spécial) :
- ansible.posix.selinux:
state: disabled
notify: Reboot systemstate: disabled nécessite un reboot pour prendre effet (le kernel doit
recharger la politique). Le module modifie /etc/selinux/config mais
getenforce continuera à afficher Enforcing jusqu'au reboot.
Les booléens SELinux sont des switches qui activent/désactivent des règles de la politique. Ex : autoriser httpd à se connecter au réseau.
- name: Lister les booleens HTTPD
ansible.builtin.command: getsebool -a
register: bools
changed_when: false
- name: Filtrer ceux contenant "httpd"
ansible.builtin.debug:
msg: "{{ bools.stdout_lines | select('search', 'httpd') | list | first(5) }}"🔍 Observation : sur RHEL 10, on a ~300 booléens. Les plus utiles RHCE :
| Booléen | Effet |
|---|---|
httpd_can_network_connect |
httpd peut faire des connexions sortantes |
httpd_can_network_connect_db |
httpd peut se connecter à une DB distante |
httpd_enable_homedirs |
httpd peut servir ~user/public_html/ |
nfs_export_all_rw |
NFS export en read-write |
samba_enable_home_dirs |
Samba peut partager les homes |
- name: Autoriser httpd a se connecter au reseau (persistant)
ansible.posix.seboolean:
name: httpd_can_network_connect
state: true
persistent: true🔍 Observation :
- Sans
persistent: true: changement uniquement runtime (perdu au reboot, équivalentsetseboolsimple). - Avec
persistent: true: changement persisté dans la politique (équivalentsetsebool -P).
Pour la production : toujours persistent: true. Sans ça, après reboot
le service replante avec les mêmes erreurs SELinux.
Pattern fréquent : déployer une app web dans un dossier custom (pas
/var/www/html/). SELinux refuse à httpd de servir des fichiers qui n'ont
pas le bon contexte SELinux.
- name: Definir le contexte httpd_sys_content_t pour /var/www/myapp
community.general.sefcontext:
target: '/var/www/myapp(/.*)?'
setype: httpd_sys_content_t
state: present
- name: Appliquer le contexte (restorecon)
ansible.builtin.command: restorecon -Rv /var/www/myapp
register: restorecon_result
changed_when: "'relabeled' in restorecon_result.stdout"🔍 Observation :
sefcontext:ajoute la règle dans la politique (semanage fcontext -a -t httpd_sys_content_t '/var/www/myapp(/.*)?').restorecon -Rapplique la règle aux fichiers existants (sinon ils gardent leur ancien contexte).
Convention regex : (/.*)? à la fin pour matcher le dossier ET tous ses
sous-éléments.
- name: Tenter d acceder a /var/www/myapp via httpd
ansible.builtin.uri:
url: http://localhost/myapp/
status_code: [200, 403] # On accepte 403 si SELinux bloque
- name: Verifier les violations dans audit.log
ansible.builtin.command: |
grep "denied" /var/log/audit/audit.log | tail -5
register: denials
changed_when: false
failed_when: false🔍 Observation : si SELinux bloque, audit.log contient des entries
type=AVC msg=audit ... denied. Outil audit2allow (paquet
policycoreutils-python-utils) génère un module SELinux qui autorise
exactement ce qui est bloqué :
ssh [email protected] 'sudo audit2allow -a -M myapp_local'
sudo semodule -i myapp_local.ppMais : ne jamais audit2allow -a -M aveuglément en prod — c'est
souvent une mauvaise idée. Préférer corriger le contexte (sefcontext) ou
activer un booléen.
Pattern dangereux observé en prod :
# ❌ Mauvaise pratique — desactive SELinux "pour que ca marche"
- ansible.posix.selinux:
state: disabled🔍 Risques :
- Surface d'attaque augmentée : SELinux est une couche de défense critique contre les exploits.
- Audit échoué : RHCE EX294, CIS Benchmark, ANSSI exigent SELinux activé.
- Drift dev/prod : le code marche en dev (SELinux off) mais plante en prod (SELinux on).
Bonne pratique : passer en permissive pour debug → identifier les
contextes/booléens manquants → corriger → revenir en enforcing.
ansible.posix.selinux:= état global (enforcing/permissive/disabled).ansible.posix.seboolean:= booléens — toujourspersistent: trueen prod.community.general.sefcontext:+restorecon -R= contextes de fichiers.- Changement vers
disablednécessite un reboot pour prendre effet. policycoreutils-python-utilsdoit être installé sur le managed node.- Ne jamais désactiver SELinux sauf cas critique documenté.
-
Vous déployez une app dans
/opt/myapp/qui doit être servie par httpd.httpdne peut pas y accéder. Quel pipeline (booléen, sefcontext, restorecon) ? -
Pourquoi
state: permissiveest-il plus utile questate: disabledpour le debug ? (indice : violations toujours loguées). -
Vous voulez lister tous les contextes définis sur un dossier. Quelle commande shell + quel module Ansible ?
Voir challenge/README.md pour la validation pytest+testinfra.
ansible.posix.seport:: associer un port à un type SELinux. Ex : faire tourner httpd sur 8080 (par défaut SELinux n'autorise httpd que sur 80, 443, 8080, etc.).audit2allow -a: générer un module SELinux custom depuis les violations loguées. Outil de dépannage — pas de production aveugle.- Multi-policy : RHEL 10 supporte
targeted(par défaut) etmls(Multi-Level Security, secteur défense). Pas dans RHCE. semanageCLI : commande de référence pour explorer la politique (semanage fcontext -l,semanage port -l,semanage boolean -l).- Lab 44 (firewalld) : compléter SELinux par les règles réseau pour une sécurité défense-en-profondeur.
Avant de lancer pytest, validez la qualité de votre lab.yml et de votre
challenge/solution.yml avec ansible-lint :
# Lint de votre fichier de lab (tutoriel guidé)
ansible-lint labs/modules-rhel/selinux/lab.yml
# Lint de votre solution challenge
ansible-lint labs/modules-rhel/selinux/challenge/solution.yml
# Profil production (le plus strict — cible RHCE 2026)
ansible-lint --profile production labs/modules-rhel/selinux/challenge/solution.ymlSi ansible-lint retourne Passed: 0 failure(s), 0 warning(s), votre code
est conforme aux bonnes pratiques : FQCN explicite, name: sur chaque tâche,
modes de fichier en chaîne, idempotence respectée, modules dépréciés évités.
💡 Astuce CI : intégrez
ansible-lint --profile productiondans un hook pre-commit pour bloquer tout commit qui introduirait des anti-patterns.