Product SiteDocumentation Site

14.4. Introduction à AppArmor

14.4.1. Les principes

AppArmor est un système de contrôle d'accès obligatoire (Mandatory Access Control) qui s'appuie sur l'interface Linux Security Modules fournie par le noyau Linux. Concrètement, le noyau interroge AppArmor avant chaque appel système pour savoir si le processus est autorisé à effectuer l'opération concernée. Ce mécanisme permet à AppArmor de confiner des programmes à un ensemble restreint de ressources.
AppArmor applique un ensemble de règles (un « profil ») à chaque programme. Le profil appliqué par le noyau dépend du chemin d'installation du programme à exécuter. Contrairement à SELinux (décrit dans Section 14.5, « Introduction à SELinux »), les règles appliquées ne dépendent pas de l'utilisateur : tous les utilisateurs sont concernés par le même jeu de règles lorsqu'ils exécutent le même programme (mais les permissions habituelles des utilisateurs jouent toujours, ce qui peut donner un comportement différent).
Les profils AppArmor sont stockés dans /etc/apparmor.d/ ; ils consistent en une liste de règles de contrôle d'accès sur les ressources que peut utiliser chaque programme. Les profils sont compilés et chargés dans le noyau par le biais de la commande apparmor_parser. Chaque profil peut être chargé soit en mode strict (enforcing) soit en mode relâché (complaining). Le mode strict applique les règles et rapporte les tentatives de violation, alors que le mode relâché se contente d'enregistrer dans les journaux système les appels système qui auraient été bloqués, sans les bloquer réellement.

14.4.2. Activer AppArmor et gérer les profils

Le support d'AppArmor est intégré aux noyaux standards fournis par Debian. Pour activer AppArmor, il suffira donc d'installer quelques paquets et d'ajouter quelques paramètres à la ligne de commande du noyau :
# apt install apparmor apparmor-profiles apparmor-utils
[...]
# perl -pi -e 's,GRUB_CMDLINE_LINUX="(.*)"$,GRUB_CMDLINE_LINUX="$1 apparmor=1 security=apparmor",' /etc/default/grub
# update-grub
Après un redémarrage, AppArmor sera opérationnel, ce que confirmera aa-status :
# aa-status
apparmor module is loaded.
44 profiles are loaded.
9 profiles are in enforce mode.
   /usr/bin/lxc-start
   /usr/lib/chromium-browser/chromium-browser//browser_java
[...]
35 profiles are in complain mode.
   /sbin/klogd
[...]
3 processes have profiles defined.
1 processes are in enforce mode.
   /usr/sbin/libvirtd (1295) 
2 processes are in complain mode.
   /usr/sbin/avahi-daemon (941) 
   /usr/sbin/avahi-daemon (1000) 
0 processes are unconfined but have a profile defined.
Le statut de chaque profil peut être basculé entre les modes strict et relâché, avec les commandes aa-enforce et aa-complain, en leur passant en paramètre soit le chemin de l'exécutable concerné, soit le chemin du fichier de profil. Il est également possible de désactiver complètement un profil avec aa-disable, ou de le basculer en mode audit (de sorte qu'il enregistre dans les journaux même les appels système acceptés) avec aa-audit.
# aa-enforce /usr/sbin/avahi-daemon
Setting /usr/sbin/avahi-daemon to enforce mode.
# aa-complain /etc/apparmor.d/usr.bin.lxc-start
Setting /etc/apparmor.d/usr.bin.lxc-start to complain mode.

14.4.3. Créer un nouveau profil

Bien qu'il soit assez simple de créer un profil AppArmor, peu de programmes en fournissent un. Cette section montre comment créer un nouveau profil depuis zéro, simplement en utilisant le programme visé et en indiquant à AppArmor de surveiller les appels système qu'il passe et les ressources qu'il utilise.
Les programmes qui devront être confinés en priorité sont ceux qui font face au réseau, car ce sont eux qui seront les cibles les plus alléchantes pour des attaquants distants. C'est précisément dans ce but qu'AppArmor fournit une commande aa-unconfined, qui liste les programmes qui, sans avoir de profil associé, exposent quand même un port de communication. L'option --paranoid liste même tous les processus non confinés qui ont au moins une connexion réseau ouverte.
# aa-unconfined
801 /sbin/dhclient not confined
890 /sbin/rpcbind not confined
899 /sbin/rpc.statd not confined
929 /usr/sbin/sshd not confined
941 /usr/sbin/avahi-daemon confined by '/usr/sbin/avahi-daemon (complain)'
988 /usr/sbin/minissdpd not confined
1276 /usr/sbin/exim4 not confined
1485 /usr/lib/erlang/erts-6.2/bin/epmd not confined
1751 /usr/lib/erlang/erts-6.2/bin/beam.smp not confined
19592 /usr/lib/dleyna-renderer/dleyna-renderer-service not confined
Dans l'exemple suivant, nous allons nous atteler à créer un profil pour /sbin/dhclient. Nous allons pour cela utiliser la commande aa-genprof dhclient, qui nous invite à utiliser l'application (dans une autre fenêtre) et à revenir à aa-genprof une fois que c'est fait, pour scruter les journaux à la recherche d'événements AppArmor et convertir ces journaux en règles de contrôle d'accès. Pour chaque événement enregistré, une ou plusieurs suggestions de règles seront proposées, et il sera possible de les approuver telles quelles ou de les modifier de diverses manières :
# aa-genprof dhclient
Writing updated profile for /sbin/dhclient.
Setting /sbin/dhclient to complain mode.

Before you begin, you may wish to check if a
profile already exists for the application you
wish to confine. See the following wiki page for
more information:
http://wiki.apparmor.net/index.php/Profiles

Please start the application to be profiled in
another window and exercise its functionality now.

Once completed, select the "Scan" option below in 
order to scan the system logs for AppArmor events. 

For each AppArmor event, you will be given the 
opportunity to choose whether the access should be 
allowed or denied.

Profiling: /sbin/dhclient

[(S)can system log for AppArmor events] / (F)inish
Reading log entries from /var/log/audit/audit.log.

Profile:  /sbin/dhclient 1
Execute:  /usr/lib/NetworkManager/nm-dhcp-helper
Severity: unknown

(I)nherit / (C)hild / (P)rofile / (N)amed / (U)nconfined / (X) ix On / (D)eny / Abo(r)t / (F)inish
P
Should AppArmor sanitise the environment when
switching profiles?

Sanitising environment is more secure,
but some applications depend on the presence
of LD_PRELOAD or LD_LIBRARY_PATH.

(Y)es / [(N)o]
Y
Writing updated profile for /usr/lib/NetworkManager/nm-dhcp-helper.
Complain-mode changes:
WARN: unknown capability: CAP_net_raw

Profile:    /sbin/dhclient 2
Capability: net_raw
Severity:   unknown

[(A)llow] / (D)eny / (I)gnore / Audi(t) / Abo(r)t / (F)inish
A
Adding capability net_raw to profile.

Profile:  /sbin/dhclient 3
Path:     /etc/nsswitch.conf
Mode:     r
Severity: unknown

  1 - #include <abstractions/apache2-common> 
  2 - #include <abstractions/libvirt-qemu> 
  3 - #include <abstractions/nameservice> 
  4 - #include <abstractions/totem> 
 [5 - /etc/nsswitch.conf]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
3

Profile:  /sbin/dhclient
Path:     /etc/nsswitch.conf
Mode:     r
Severity: unknown

  1 - #include <abstractions/apache2-common> 
  2 - #include <abstractions/libvirt-qemu> 
 [3 - #include <abstractions/nameservice>]
  4 - #include <abstractions/totem> 
  5 - /etc/nsswitch.conf 
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding #include <abstractions/nameservice> to profile.

Profile:  /sbin/dhclient
Path:     /proc/7252/net/dev
Mode:     r
Severity: 6

  1 - /proc/7252/net/dev 
 [2 - /proc/*/net/dev]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /proc/*/net/dev r to profile

[...]
Profile:  /sbin/dhclient 4
Path:     /run/dhclient-eth0.pid
Mode:     w
Severity: unknown

 [1 - /run/dhclient-eth0.pid]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
N

Enter new path: /run/dhclient*.pid

Profile:  /sbin/dhclient
Path:     /run/dhclient-eth0.pid
Mode:     w
Severity: unknown

  1 - /run/dhclient-eth0.pid 
 [2 - /run/dhclient*.pid]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /run/dhclient*.pid w to profile

[...]
Profile:  /usr/lib/NetworkManager/nm-dhcp-helper 5
Path:     /proc/filesystems
Mode:     r
Severity: 6

 [1 - /proc/filesystems]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /proc/filesystems r to profile

= Changed Local Profiles =

The following local profiles were changed. Would you like to save them?

 [1 - /sbin/dhclient]
  2 - /usr/lib/NetworkManager/nm-dhcp-helper 
(S)ave Changes / Save Selec(t)ed Profile / [(V)iew Changes] / View Changes b/w (C)lean profiles / Abo(r)t
S
Writing updated profile for /sbin/dhclient.
Writing updated profile for /usr/lib/NetworkManager/nm-dhcp-helper.

Profiling: /sbin/dhclient

[(S)can system log for AppArmor events] / (F)inish
F
Setting /sbin/dhclient to enforce mode.
Setting /usr/lib/NetworkManager/nm-dhcp-helper to enforce mode.

Reloaded AppArmor profiles in enforce mode.

Please consider contributing your new profile!
See the following wiki page for more information:
http://wiki.apparmor.net/index.php/Profiles

Finished generating profile for /sbin/dhclient.
Il faut noter que le programme n'affiche pas les caractères de contrôle tapés ; nous les avons inclus dans la transcription ci-dessus pour clarifier les choses.

1

Le premier événement détecté est l'exécution d'un autre programme. Dans ce cas, plusieurs choix s'offrent à nous : on peut soit lancer le programme avec le profil du programme parent (Inherit), soit le lancer avec un profil dédié (Profile et Name, qui ne diffèrent que par la possibilité de choisir un nom de profil arbitraire), soit le lancer avec un sous-profil du processus parent (Child), soit le lancer sans aucun profil (Unconfined), soit ne pas le lancer du tout (Deny).
À noter que lorsque l'on choisit de lancer le processus fils selon un profil dédié mais qui n'existe pas encore, l'outil va créer le profil manquant, et proposer des suggestions de règles par la même occasion.

2

Au niveau du noyau, les pouvoirs spéciaux de l'utilisateur root ont été séparés en « capacités ». Lorsqu'un appel système a besoin d'une capacité spécifique, AppArmor va vérifier que le profil permet au programme d'utiliser cette capacité.

3

Ici, le programme requiert les permissions de lecture sur /etc/nsswitch.conf. aa-genprof a détecté que cette permission était déjà accordée par plusieurs « abstractions », et les offre comme des choix possibles. Une abstraction fournit un ensemble réutilisable de règles de contrôle d'accès, en regroupant des règles qui sont souvent utilisées de concert. Dans notre cas précis, ce fichier est généralement utilisé par les fonctions de la bibliothèque C standard liées à la résolution de noms, et nous choisissons donc « 3 » pour inclure le choix « #include <abstractions/nameservice> », puis « A » pour l'autoriser.

4

Le programme essaie de créer le fichier /run/dhclient-eth0.pid. Si nous autorisons seulement la création de ce fichier, le programme ne fonctionnera plus lorsque l'utilisateur essaiera de l'utiliser sur une autre interface réseau. Nous choisissons donc « New » pour remplacer le nom de fichier par un nom plus générique, « /run/dhclient*.pid », avant d'enregistrer la règle avec « Allow ».

5

Notons que cette tentative d'accès ne fait pas partie du profil dhclient, mais du nouveau profil que nous avons créé lorsque nous avons autorisé /usr/lib/NetworkManager/nm-dhcp-helper à fonctionner sous son propre profil.
Une fois que tous les événements enregistrés ont été examinés, le programme propose de sauver tous les profils qui ont été créés pendant l'exécution. Dans notre cas, nous avons deux profils que nous enregistrons d'un coup avec « Save » (mais nous aurions aussi pu les enregistrer un par un) avant de quitter le programme avec « Finish ».
aa-genprof n'est en fait qu'un petit script intelligent qui utilise aa-logprof : il crée un profil vide, le charge en mode relâché, puis lance aa-logprof. Ce dernier est un outil qui met à jour un profil en fonction des violations qui ont été enregistrées. On peut donc relancer cet outil plus tard, de manière à améliorer le profil nouvellement créé.
Pour que le profil généré soit complet, il faut utiliser le programme de toutes les manières légitimement possibles. Dans le cas de dhclient, cela implique de le lancer via Network Manager, mais aussi via ifupdown, à la main, etc. À la fin, on obtient un /etc/apparmor.d/sbin.dhclient qui ressemble à ceci :
# Last Modified: Tue Sep  8 21:40:02 2015
#include <tunables/global>

/sbin/dhclient {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  capability net_bind_service,
  capability net_raw,

  /bin/dash r,
  /etc/dhcp/* r,
  /etc/dhcp/dhclient-enter-hooks.d/* r,
  /etc/dhcp/dhclient-exit-hooks.d/* r,
  /etc/resolv.conf.* w,
  /etc/samba/dhcp.conf.* w,
  /proc/*/net/dev r,
  /proc/filesystems r,
  /run/dhclient*.pid w,
  /sbin/dhclient mr,
  /sbin/dhclient-script rCx,
  /usr/lib/NetworkManager/nm-dhcp-helper Px,
  /var/lib/NetworkManager/* r,
  /var/lib/NetworkManager/*.lease rw,
  /var/lib/dhcp/*.leases rw,

  profile /sbin/dhclient-script flags=(complain) {
    #include <abstractions/base>
    #include <abstractions/bash>

    /bin/dash rix,
    /etc/dhcp/dhclient-enter-hooks.d/* r,
    /etc/dhcp/dhclient-exit-hooks.d/* r,
    /sbin/dhclient-script r,

  }
}