AppArmor en 2026 : guide complet pour écrire, tester et déployer des profils de sécurité sur Linux

Guide pratique 2026 pour écrire, tester et déployer des profils AppArmor sur Linux. Modes complain/enforce, aa-genprof, intégration systemd et conteneurs Docker.

Guide AppArmor 4.x : Profils Linux 2026

Mis à jour : 31 mai 2026

AppArmor est un module de sécurité Linux (LSM) qui confine chaque processus à l'aide de profils déclaratifs basés sur les chemins, limitant les fichiers qu'il peut lire, les sockets qu'il peut ouvrir et les capabilities qu'il peut invoquer. Dans ce guide, vous allez apprendre comment écrire un profil AppArmor depuis zéro avec aa-genprof, comment basculer entre les modes complain et enforce, comment réutiliser les abstractions de la version 4.x sortie en 2024, et comment intégrer le tout à systemd pour durcir vos services en production sans casser la disponibilité. Honnêtement, c'est l'une des compétences qui m'a le plus servi en SRE ces deux dernières années.

  • AppArmor 4.x (livré dans Ubuntu 24.04 LTS et Debian 13 « Trixie ») introduit la résolution conditionnelle, les règles io_uring et un parser nettement plus rapide.
  • Le mode complain journalise les violations sans les bloquer : c'est le seul mode acceptable pour développer un nouveau profil en production.
  • aa-genprof et aa-logprof génèrent automatiquement des règles à partir des entrées audit, mais demandent toujours une révision humaine avant l'enforcement.
  • Les abstractions (abstractions/base, abstractions/nameservice) factorisent les permissions communes et évitent les profils de 800 lignes.
  • Une directive AppArmorProfile= dans une unité systemd applique un profil par-service sans modifier les binaires.
  • AppArmor et SELinux ne peuvent pas coexister activement : le choix se fait au démarrage du noyau via le paramètre lsm=.

Qu'est-ce qu'AppArmor et comment fonctionne-t-il ?

AppArmor (pour « Application Armor ») est l'un des trois Linux Security Modules (LSM) officiellement supportés par le noyau, aux côtés de SELinux et de Smack. Contrairement à la sécurité Unix classique fondée sur les permissions discrétionnaires (DAC), AppArmor implémente un modèle de contrôle d'accès obligatoire (MAC). Les règles sont décidées par l'administrateur et le noyau les applique, indépendamment des droits effectifs de l'utilisateur. Un processus root confiné par AppArmor ne peut pas s'évader de son profil, même s'il appelle setuid(0) ou détourne une bibliothèque vulnérable.

La singularité d'AppArmor, c'est son approche basée sur les chemins. Là où SELinux associe un label persistant à chaque inode (objet du système de fichiers), AppArmor évalue les règles selon le chemin canonique observé au moment de l'accès. Ce choix simplifie radicalement la rédaction des profils : un développeur qui connaît son application sait quels fichiers elle ouvre, mais ignore généralement les labels SELinux à appliquer.

En contrepartie, un attaquant capable de remonter un point de montage ou de créer un lien symbolique peut, dans certains scénarios, contourner une règle mal écrite. D'où l'importance des restrictions mount et link introduites avec AppArmor 3.

Le projet est maintenu principalement par Canonical et SUSE. La version 4.0.0, publiée en avril 2024 et embarquée par défaut dans Ubuntu 24.04 LTS « Noble Numbat », apporte la résolution conditionnelle de profils, la médiation io_uring et un nouveau parser écrit en Rust qui réduit le temps de compilation de la policy d'environ 40 %.

Installer et activer AppArmor sur Ubuntu, Debian et openSUSE

AppArmor est pré-installé et activé sur Ubuntu depuis la 7.10, et sur openSUSE depuis la 10.1. Sur Debian, il est livré mais désactivé par défaut jusqu'à Debian 10 ; depuis Debian 11 « Bullseye », il est activé au boot. Pour vérifier l'état actuel du module et lister les profils chargés :

# Vérifier que le LSM est actif dans le noyau
cat /sys/kernel/security/lsm
# attendu : capability,landlock,lockdown,yama,apparmor

# Statut détaillé : profils en enforce / complain et processus confinés
sudo aa-status

# Installer les outils userspace si nécessaire
sudo apt install -y apparmor apparmor-utils apparmor-profiles apparmor-profiles-extra

Si la commande aa-status renvoie « apparmor module is not loaded », activez le LSM au boot en ajoutant apparmor=1 security=apparmor lsm=landlock,lockdown,yama,integrity,apparmor à la ligne GRUB_CMDLINE_LINUX_DEFAULT dans /etc/default/grub, puis exécutez sudo update-grub et redémarrez. Sur openSUSE, le service apparmor.service charge les profils ; sur Debian/Ubuntu, c'est aussi apparmor.service via systemd, et /etc/apparmor.d/ qui contient l'arbre des profils.

Anatomie d'un profil AppArmor en 2026

Un profil AppArmor est un fichier texte situé dans /etc/apparmor.d/, nommé d'après le chemin du binaire confiné (les / deviennent des .). Voici un profil minimal pour un script d'archivage personnalisé, qui illustre les sept éléments syntaxiques que vous croiserez le plus souvent :

# /etc/apparmor.d/usr.local.bin.backup-script
abi <abi/4.0>,                       # version d'ABI du profil

include <tunables/global>            # variables @{HOME}, @{PROC}, etc.

profile backup-script /usr/local/bin/backup-script {
  include <abstractions/base>        # libc, locale, dns
  include <abstractions/consoles>

  capability dac_read_search,         # lire des fichiers d'autres utilisateurs
  capability net_bind_service,

  network inet stream,                # autoriser TCP/IPv4 sortant

  /usr/local/bin/backup-script r,     # le binaire lui-même
  /etc/backup.conf r,
  /var/log/backup/*.log w,
  /srv/data/** r,                     # ** = récursif
  /mnt/backup/** rwk,                 # k = locking

  deny /etc/shadow rwklx,             # interdiction explicite
  deny @{HOME}/.ssh/** rwklx,

  /usr/bin/tar Ux,                    # exécution non confinée
  /usr/bin/rsync Cx -> backup-rsync,  # exécution dans un sous-profil
}

Les permissions les plus courantes sont r (lecture), w (écriture), k (verrouillage), m (mmap exécutable), x (exécution). Les variantes de x méritent une attention particulière. ix hérite du profil parent, px applique un profil discret existant, Px nettoie l'environnement avant, ux sort du confinement (à proscrire en production), Cx applique un sous-profil défini dans le même fichier.

Choisir le mauvais modificateur, c'est la première cause d'évasion silencieuse que j'ai rencontrée en audit. Toujours préférer Px ou Cx à ux.

Comment créer un profil AppArmor avec aa-genprof ?

L'outil aa-genprof automatise la phase la plus ingrate du travail : observer toutes les ressources qu'une application touche, et écrire les règles correspondantes. Le workflow typique se déroule en quatre temps. D'abord, lancez aa-genprof dans un terminal pour démarrer l'enregistrement :

sudo aa-genprof /usr/local/bin/backup-script

L'outil crée un profil squelette en mode complain, l'active, puis attend. Dans un second terminal, exécutez l'application en couvrant tous ses cas d'usage : démarrage, traitement nominal, rechargement de configuration, arrêt propre, gestion d'erreurs. Plus la couverture est large, moins vous aurez de refus en production. Revenez ensuite au premier terminal et appuyez sur S (scan) ; aa-genprof parcourt /var/log/audit/audit.log ou /var/log/syslog, présente chaque événement et propose une règle. Pour chacune, choisissez A (allow), D (deny), I (inherit), G (glob, pour généraliser à /var/log/*.log) ou N (new, pour créer un sous-profil). Validez par F (finish) qui sauvegarde le profil dans /etc/apparmor.d/.

Une fois en production, utilisez aa-logprof régulièrement pour intégrer les nouveaux événements générés par des chemins de code rares (cron mensuel, migration de base de données…). Le couple complain + aa-logprof hebdomadaire, c'est ce qui distingue un déploiement AppArmor mature d'un profil figé qui finit invariablement par bloquer une fonctionnalité légitime.

Modes complain vs enforce : workflow recommandé

Chaque profil AppArmor est en permanence dans l'un de deux états. En complain, le noyau journalise toute action qui aurait été refusée mais l'autorise. En enforce, les violations sont bloquées avec un code EACCES renvoyé à l'application. Bascule manuelle :

# Passer un profil en complain (création d'un lien dans force-complain/)
sudo aa-complain /etc/apparmor.d/usr.local.bin.backup-script

# Passer un profil en enforce
sudo aa-enforce /etc/apparmor.d/usr.local.bin.backup-script

# Désactiver complètement un profil (lien dans disable/)
sudo aa-disable /etc/apparmor.d/usr.local.bin.backup-script

# Recharger sans redémarrer le service
sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.backup-script

Le workflow éprouvé en SRE ressemble à ceci : (1) déployer le profil en complain pendant au moins une semaine pour capturer le cycle hebdomadaire complet ; (2) lancer aa-logprof et valider chaque règle ; (3) basculer en enforce sur un canary (1 à 5 % du parc) ; (4) surveiller le taux d'erreur applicatif et les refus AppArmor pendant 48 h ; (5) rouler progressivement à 100 %.

Sauter l'étape canary, c'est la cause la plus fréquente d'incidents post-déploiement. J'ai vu ça notamment sur des applications Java qui ouvrent des chemins JIT temporaires non couverts par les tests fonctionnels. Pas drôle à 3 h du matin.

Abstractions, tunables et includes : réutiliser les briques

Plutôt que de répéter 50 lignes de règles pour la libc, le DNS ou les locales dans chaque profil, AppArmor fournit des abstractions dans /etc/apparmor.d/abstractions/. Les plus utiles :

  • abstractions/base : libc, ld.so, locales, /dev/null, /dev/urandom. Incluse dans 99 % des profils.
  • abstractions/nameservice : résolution DNS (nss, /etc/resolv.conf, /etc/hosts).
  • abstractions/openssl : accès aux CA-bundle, /dev/urandom, OpenSSL config.
  • abstractions/python, abstractions/perl, abstractions/ruby : interpréteurs et site-packages.
  • abstractions/nis, abstractions/wutmp : journaux d'authentification et accounting.

Les tunables dans /etc/apparmor.d/tunables/ sont des variables réutilisables. @{HOME}, @{PROC}, @{pid} et @{multiarch} sont les plus courantes. Elles évitent de coder en dur /home/*/ ou /proc/[0-9]*/. Vous pouvez surcharger une tunable dans /etc/apparmor.d/tunables/home.d/ pour adapter le chemin sans toucher au profil. Cette indirection s'avère précieuse en environnement immuable où les /home sont montés depuis NFS dans /srv/users/. Pour un panorama plus large des protections complémentaires au niveau noyau, jetez un œil à notre guide de durcissement nftables.

Confiner un service systemd avec AppArmorProfile

Depuis systemd 235, la directive AppArmorProfile= applique un profil au moment du fork/exec du service, sans avoir besoin de modifier le binaire ni d'ajouter de wrapper. Exemple complet pour un microservice Go exposé sur le port 8080 :

# /etc/systemd/system/api-gateway.service
[Unit]
Description=API Gateway interne
After=network-online.target

[Service]
Type=exec
ExecStart=/usr/local/bin/api-gateway --config /etc/api-gateway/config.yaml
Restart=on-failure
User=apigw
Group=apigw

# Confinement AppArmor (le profil doit déjà être chargé)
AppArmorProfile=api-gateway

# Durcissement systemd complémentaire
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/api-gateway /var/log/api-gateway

[Install]
WantedBy=multi-user.target

Combiner AppArmor avec les directives Protect*, NoNewPrivileges=true et un utilisateur dédié forme une vraie défense en profondeur. Si un attaquant contourne une règle AppArmor mal écrite, il se heurte au namespace systemd. S'il s'évade du namespace, le profil AppArmor reste actif. Pour automatiser l'audit de ces couches sur l'ensemble d'un parc, beaucoup d'équipes l'intègrent à leur pipeline avec des outils complémentaires comme ceux décrits dans notre guide de sécurisation de la chaîne d'approvisionnement logicielle.

AppArmor et conteneurs Docker / Podman

Docker charge automatiquement un profil par défaut nommé docker-default à chaque démarrage de conteneur si AppArmor est actif sur l'hôte. Vous pouvez le remplacer par un profil personnalisé via l'option --security-opt apparmor=mon-profil. Avantage par rapport aux seccomp : la granularité par chemin du système de fichiers, particulièrement utile pour interdire l'écriture dans des volumes mountés en lecture/écriture par défaut.

# Charger un profil personnalisé sur l'hôte
sudo apparmor_parser -r /etc/apparmor.d/mon-conteneur

# Lancer le conteneur avec ce profil
docker run --security-opt apparmor=mon-conteneur \
           --read-only --tmpfs /tmp \
           -p 8080:8080 nginx:1.27-alpine

# Vérifier le profil appliqué au PID du conteneur
PID=$(docker inspect --format '{{.State.Pid}}' <container>)
sudo cat /proc/$PID/attr/current
# attendu : mon-conteneur (enforce)

Podman fonctionne de manière identique en mode rootful. En mode rootless, AppArmor reste appliqué mais ne peut pas être modifié dynamiquement par l'utilisateur, et le profil doit être chargé au préalable par l'administrateur. Sur Kubernetes, l'annotation container.apparmor.security.beta.kubernetes.io/<container> a été promue GA dans la 1.30 et remplacée par le champ securityContext.appArmorProfile, désormais standard. Pour les workloads conteneurisés, complétez AppArmor avec une couche de détection runtime comme décrit dans notre guide eBPF Falco et Tetragon.

AppArmor vs SELinux : quelle différence ?

Les deux modules atteignent le même objectif (confinement obligatoire des processus) mais avec des philosophies opposées. Tableau de comparaison synthétique :

CritèreAppArmorSELinux
ModèleBasé sur les cheminsBasé sur les labels (type enforcement)
Courbe d'apprentissageModérée, syntaxe lisibleRaide, concepts MLS, MCS, RBAC
Distributions par défautUbuntu, Debian, openSUSERHEL, Fedora, CentOS Stream, Rocky, Alma
Stockage des règlesFichiers texte dans /etc/apparmor.d/Politique compilée (.pp) + labels sur inodes
Survit aux renommagesNon, le chemin change, le profil ne s'applique plusOui, le label suit l'inode
Modescomplain / enforce / disablepermissive / enforcing / disabled
Outil d'apprentissage autoaa-genprof, aa-logprofaudit2allow
Coexistence dans le noyauMutuellement exclusifs : un seul actif à la fois

Le choix dépend généralement de la distribution. Si vous administrez du RHEL, restez sur SELinux car toute la documentation et tous les profils livrés sont pensés pour lui. Si vous gérez du Ubuntu/Debian, AppArmor offre un meilleur rapport effort/résultat. La documentation officielle SUSE reste la référence la plus complète sur AppArmor en environnement entreprise, et la documentation Ubuntu couvre bien le cas d'usage desktop et serveur courant.

Débogage : lire les journaux audit et corriger les refus

Quand une application légitime est bloquée, le diagnostic se fait en quatre étapes. D'abord, vérifier que le profil est bien en enforce : sudo aa-status | grep mon-app. Ensuite, extraire les refus du journal audit :

# Sur Ubuntu/Debian (sans auditd)
sudo dmesg | grep -i 'apparmor="DENIED"'
sudo journalctl -k --since "10 minutes ago" | grep apparmor

# Sur systèmes avec auditd (RHEL/SUSE/Debian)
sudo ausearch -m AVC -ts recent | aa-decode

# Format typique d'un refus :
# apparmor="DENIED" operation="open" profile="mon-app"
#   name="/var/lib/mon-app/cache.db" pid=4521 comm="mon-app"
#   requested_mask="wc" denied_mask="wc" fsuid=998 ouid=998

Troisième étape : décider si la règle manquante est légitime (auquel cas, l'ajouter au profil et recharger avec apparmor_parser -r) ou si l'application tente effectivement une opération interdite (auquel cas le blocage est correct). Enfin, pour reproduire le problème en environnement de pré-prod, basculez momentanément le profil en complain, exécutez la suite de tests fonctionnels, puis utilisez aa-logprof pour intégrer les règles manquantes.

Ne jamais désactiver le profil en production comme « solution ». C'est une dette de sécurité qui ne sera jamais remboursée (je parle d'expérience).

Questions fréquentes

Comment désactiver AppArmor temporairement sans redémarrer ?

Utilisez sudo aa-teardown pour décharger tous les profils chargés, ou sudo aa-disable /etc/apparmor.d/<profil> pour ne désactiver qu'un profil précis. Pour désactiver AppArmor de façon permanente, retirez apparmor du paramètre lsm= de GRUB et redémarrez. Mais franchement, préférez basculer les profils gênants en mode complain.

Pourquoi mon profil ne s'applique-t-il pas après aa-enforce ?

Trois causes typiques : (1) le processus était déjà lancé avant le chargement du profil, AppArmor applique le profil au fork/exec, pas rétroactivement, donc redémarrez le service ; (2) le binaire a été appelé via un chemin différent (lien symbolique, /usr/local/bin/ vs /usr/bin/), utilisez le chemin canonique avec realpath ; (3) le profil est en mode disable, vérifiez avec aa-status.

AppArmor ralentit-il les performances système ?

L'impact mesuré est inférieur à 1 % sur les charges de travail typiques (serveur web, base de données, microservices). Les opérations très open/exec-intensives (build C++, scan de fichiers) peuvent voir jusqu'à 3 à 5 % de surcoût. Le parser réécrit en Rust dans AppArmor 4.x réduit également le temps de chargement initial de la politique.

Peut-on utiliser AppArmor sans systemd ?

Oui. AppArmor est un mécanisme noyau indépendant de systemd. Le script init /etc/init.d/apparmor existe toujours et fonctionne avec OpenRC, sysvinit ou runit. La directive AppArmorProfile= de systemd n'est qu'un raccourci ; vous pouvez aussi appeler aa_change_onexec() depuis n'importe quel programme C ou wrapper shell qui invoque aa-exec.

Comment savoir si un processus est confiné par un profil ?

Lisez /proc/<pid>/attr/current. La sortie au format nom_profil (enforce) ou nom_profil (complain) indique le profil actif. Une valeur unconfined signifie qu'aucun profil n'est appliqué. La commande sudo aa-status donne la vue agrégée pour tous les processus du système.

À propos de l'auteur Editorial Team

Our team of expert writers and editors.