SELinux (Security Enhanced Linux) est un mécanisme de sécurité développé pour Linux par la NSA (National Security Agency) et utilisé principalement sur les systèmes Red Hat, CentOS et Fedora. Il améliore de manière significative la sécurité des serveurs sur lesquels il est déployé, en apportant une couche supplémentaire aux traditionnels droits d’accès aux fichiers Unix. En contrepartie, sa complexité considérable conduit tôt ou tard à des erreurs de configuration, ce qui a pour conséquence que bon nombre d’administrateurs décident tôt ou tard de désactiver SELinux. L’objet de cet article, c’est de fournir une introduction simple à SELinux, en s’appuyant sur une série d’exemples pratiques.

DAC et MAC

Traditionnellement, Linux utilise le contrôle d’accès discrétionnaire (Discretionary Access Control – DAC). Une application tourne avec les droits d’un certain utilisateur, ce qui définit les fichiers, les répertoires et les périphériques auxquels elle peut accéder. Les services réseau comme les serveurs de bases de données, les serveurs web etc. démarrent avec les droits du superutilisateur root pour ensuite tourner avec les droits limités d’un utilisateur système. Ce système traditionnel des permissions Unix est assez simple à manipuler, mais ses possibilités de configuration restent limitées. Dès qu’un intrus réussit à prendre la main sur un service, il aura accès à une partie plus ou moins importante du système de fichiers, y compris des fichiers que le service en question n’utilise pas forcément.

C’est là où SELinux entre en jeu avec le principe du contrôle d’accès obligatoire (Mandatory Access Control – MAC). Pour simplifier, chaque processus est confiné à un domaine, et les fichiers sont étiquetés en conséquence. Un processus ne pourra accéder qu’aux fichier étiquetés pour le domaine auquel il est confiné.

SELinux, c’est quoi exactement ?

Plus concrètement, SELinux est une extension du kernel qui permet de surveiller des processus en cours d’exécution, en garantissant que ceux-ci respectent certaines règles. SELinux repose essentiellement sur deux fondements.

Les fichiers et les processus doivent être étiquetés avec un contexte de sécurité SELinux approprié. Nous verrons un peu plus loin ce que cela signifie concrètement.

Les processus surveillés par SELinux doivent respecter un certain nombre de règles prédéfinies. Là aussi, une série d’exemples pratiques nous permettra de comprendre de quoi il s’agit.

L’efficacité de SELinux va donc de pair avec la qualité des règles. Notons ici que seul le distributeur Red Hat s’est donné la peine de définir une collection de règles qui tiennent la route pour une utilisation professionnelle.

Les points problématiques

Comme toutes les technologies un peu pointues, SELinux présente quelques problèmes, que nous pouvons mentionner ici.

SELinux utilise les attributs étendus (Extended Attributes – EA) des fichiers pour les étiquettes. D’une part, cela nécessite des systèmes de fichiers compatibles avec les attributs étendus. D’autre part, il faudra être particulièrement vigilant lors des opérations de sauvegarde, de restauration et de mise à jour.

Sous le capot, SELinux est d’une complexité ahurissante. La protection des services les plus élémentaires d’un serveur requiert des milliers de règles. Pour l’administrateur Linux « commun mortel », SELinux peut paraître comme une « boîte noire » développée par les ingénieurs Red Hat, dont la complexité l’amènera tôt ou tard à des erreurs d’implémentation. Un coup d’oeil sur les blogs techniques divers et variés montre que les administrateurs succombent bien trop souvent à la tentation de désactiver SELinux au premier souci de configuration.

Notons au passage une critique entièrement infondée, mais qui revient régulièrement dans les discussions. SELinux est développé par la NSA, un service secret tristement célèbre pour ses opérations de surveillance à l’échelle planétaire depuis les révélations d’Edward Snowden. Partant de là, il est facile d’imaginer que la NSA en aurait profité pour glisser du code malveillant dans le kernel, qui lui permettrait d’étendre ses opérations de surveillance à toutes les machines tournant sous Linux. Avant de sombrer dans la paranoïa, notons donc que SELinux est un projet open source qui a été audité par un nombre important d’experts indépendants avant d’être officiellement inclus dans le kernel Linux.

SELinux dans tous ses états

SELinux propose trois modes différents.

Dans le mode strict ( Enforcing ), les accès sont restreints en fonction des règles SELinux en vigueur sur la machine.

( ), les accès sont restreints en fonction des règles SELinux en vigueur sur la machine. Le mode permissif ( Permissive ) peut être considéré comme un mode de débogage. Les règles SELinux sont interrogées, les erreurs d’accès sont enregistrées dans les logs, mais l’accès ne sera pas bloqué.

( ) peut être considéré comme un mode de débogage. Les règles SELinux sont interrogées, les erreurs d’accès sont enregistrées dans les logs, mais l’accès ne sera pas bloqué. Lorsque SELinux est désactivé ( Disabled ), l’accès n’est pas restreint, et rien n’est enregistré dans les logs.

La commande getenforce vous informe sur le mode en vigueur sur votre machine.

$ getenforce Enforcing

La commande setenforce permet de basculer temporairement – jusqu’au prochain redémarrage – entre les modes strict ( Enforcing ) et permissif ( Permissive ).

$ getenforce Enforcing $ sudo setenforce 0 $ getenforce Permissive $ sudo setenforce 1 $ getenforce Enforcing

Le mode SELinux par défaut est défini dans le fichier /etc/selinux/config .

# /etc/selinux/config SELINUX=enforcing SELINUXTYPE=targeted

Ici, SELINUX prendra une des trois valeurs enforcing , permissive ou disabled . Quant à SELINUXTYPE , on gardera la valeur par défaut targeted , qui garantit la surveillance des principaux services réseau.

Lorsque SELinux est activé – autrement dit, lorsqu’on passe du mode disabled à permissive ou enforcing , il faut impérativement songer à réétiqueter l’ensemble des fichiers du système. Pour ce faire, il suffit de créer un fichier vide .autorelabel à la racine du système de fichiers avant de redémarrer.

$ sudo touch /.autorelabel $ sudo reboot

Le réétiquetage du système de fichiers peut prendre un certain temps, en fonction de la taille de votre installation. Pour une première utilisation, je vous conseille d’opter pour le mode permissif par défaut. Cela évite de se retrouver avec un système qui ne démarre plus en mode strict.

Sur une installation fraîche de RHEL, CentOS ou Fedora, SELinux est activé en mode strict ( Enforcing ) par défaut.

) par défaut. Sur un serveur dédié sous CentOS chez Online, SELinux est désactivé ( Disabled ) par défaut.

Exemple pratique n° 1

Maintenant que nous disposons du minimum syndical de bagage théorique, passons à la pratique. Pour ce premier exemple, je passe en mode strict.

$ getenforce Enforcing

Je mets en place une machine « bac à sable » amandine.microlinux.lan avec un serveur Apache. Dans sa configuration par défaut, Apache est censé servir les pages web rangées dans /var/www/html . Je copie la page web par défaut à cet endroit.

$ cd /var/www/html/ $ sudo chown microlinux:microlinux . $ cp -R /usr/share/httpd/noindex/* .

J’édite la page index.html pour la différencier de la page fournie par défaut, je démarre Apache et j’obtiens ceci.

Jusqu’ici, tout va bien. J’ai réussi à configurer un hébergement web avec SELinux en mode strict, et je me sens un peu comme Monsieur Jourdain dans Le Bourgeois Gentilhomme, qui fait de la prose sans le savoir.

Notez ici que dans la configuration par défaut, Apache sert les pages web rangées dans /usr/share/httpd/noindex en l’absence de page d’index. Cette fonctionnalité peut s’avérer quelque peu déroutante pour la suite de nos manipulations. Il vaut mieux la désactiver, ce qui peut se faire simplement en commentant la directive correspondante dans le fichier /etc/httpd/conf.d/welcome.conf .

# <LocationMatch "^/+$"> # Options -Indexes # ErrorDocument 403 /.noindex.html # </LocationMatch>

Le contexte de sécurité SELinux

Le contenu de mon répertoire /var/www/html ressemble à ceci.

$ cd /var/www/html/ $ ls -l total 16 drwxr-xr-x. 3 microlinux microlinux 4096 30 janv. 15:24 css drwxr-xr-x. 2 microlinux microlinux 4096 30 janv. 15:24 images -rw-r--r--. 1 microlinux microlinux 4899 30 janv. 15:26 index.html

L’option -Z me permet d’afficher le contexte de sécurité de ces fichiers.

$ ls -Z drwxr-xr-x. microlinux microlinux unconfined_u:object_r:httpd_sys_content_t:s0 css drwxr-xr-x. microlinux microlinux unconfined_u:object_r:httpd_sys_content_t:s0 images -rw-r--r--. microlinux microlinux unconfined_u:object_r:httpd_sys_content_t:s0 index.html

Cette même option -Z peut s’utiliser avec la commande ps pour afficher le contexte de sécurité d’un processus.

# ps axZ | grep httpd system_u:system_r:httpd_t:s0 3948 ? Ss 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 3949 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 3950 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 3951 ? S 0:00 /usr/sbin/httpd -DFOREGROUND ...

Un contexte SELinux est présenté sous la forme utilisateur:rôle:type:niveau . Laissons de côté les utilisateurs SELinux, les rôles et les niveaux, et concentrons-nous sur le type, qui correspond au troisième champ dans le contexte SELinux.

unconfined_u:object_r: httpd_sys_content_t :s0

system_u:system_r:httpd_t:s0

Nous avons vu que sur le serveur web en cours d’exécution, le processus httpd est étiqueté httpd_t . Les fichiers servis par Apache semblent tous munis de l’étiquette httpd_sys_content_t . Si nous affichons le contexte de sécurité des fichiers appartenant à Apache, nous constatons qu’ils semblent tous appartenir à une même famille en termes d’étiquettes.

Les fichiers de configuration sont étiquetés httpd_config_t .

. Les fichiers logs sont tous de type httpd_log_t .

Essayons maintenant de cerner le principe de fonctionnement de SELinux en partant de cet exemple.

Il est probablement logique qu’un processus étiqueté httpd_t puisse interagir avec des fichiers étiquetés httpd_sys_content_t , httpd_config_t , httpd_log_t , etc.

puisse interagir avec des fichiers étiquetés , , , etc. En revanche, il n’est probablement pas logique qu’un processus étiqueté httpd_t puisse interagir avec un fichier comme /etc/shadow , qui porte l’étiquette shadow_t .

Faisons une petite expérience pour mieux comprendre ce principe.

Exemple pratique n° 2

Dans ce deuxième exemple, je vais copier les fichiers servis par Apache vers un répertoire en-dessous de /srv , effacer le contenu original, puis déplacer les fichiers copiés vers l’emplacement original.

$ cd /var/www/html/ $ sudo mkdir /srv/html $ sudo chown -R microlinux:microlinux /srv/html/ $ cp -R * /srv/html/ $ rm -rf * $ mv /srv/html/* .

Certains parmi vous auront le vague sentiment de tourner en rond pour revenir à la case départ. Ce n’est pas tout à fait le cas, comme nous allons le voir tout de suite. Rafraîchissez la page web qui s’affiche dans le navigateur, et voici ce que vous obtenez.

Jetons un oeil dans les logs d’Apache pour voir ce qui se passe.

$ sudo cat /var/log/httpd/error_log ... [Thu Jan 31 08:25:15.894012 2019] [core:error] [pid 4435] (13)Permission denied: [client 192.168.2.2:58016] AH00035: access to /index.html denied (filesystem path '/var/www/html/index.html') because search permissions are missing on a component of the path

Et là, nous restons quelque peu perplexes, parce que nous avons vérifié à deux fois les droits d’accès de nos fichiers, et qu’ils ont l’air corrects. Mystère et boules de gomme.

Retournons maintenant dans /var/www/html et jetons un oeil sur le contexte SELinux des fichiers.

$ cd /var/www/html/ $ ls -Z drwxr-xr-x. microlinux microlinux unconfined_u:object_r:var_t:s0 css drwxr-xr-x. microlinux microlinux unconfined_u:object_r:var_t:s0 images -rw-r--r--. microlinux microlinux unconfined_u:object_r:var_t:s0 index.html

L’administrateur perplexe souhaite sans doute en savoir un peu plus sur le pourquoi du comment de ce refus d’obtempérer. Les logs de SELinux ne sont pas ce qu’il y a de plus lisible, mais fort heureusement, il existe un outil pratique pour nous faciliter la tâche. Installez le paquet setroubleshoot-server et invoquez la commande suivante.

$ sudo sealert -a /var/log/audit/audit.log | less 100% done found 1 alerts in /var/log/audit/audit.log -------------------------------------------------------- SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/index.html. ***** Plugin restorecon (94.8 confidence) suggests ***** If you want to fix the label. /var/www/html/index.html default label should be httpd_sys_content_t. Then you can run restorecon. The access attempt may have been stopped due to insufficient permissions to access a parent directory in which case try to change the following command accordingly. Do # /sbin/restorecon -v /var/www/html/index.html ...

Notez au passage qu’ici, j’ai invoqué la commande sur un serveur configuré en anglais ( LANG=en_US.utf8 ). Sur un système configuré en français, on obtient un mélange de français et d’anglais assez folklorique.

Quoi qu’il en soit, retenons le contenu de ce message d’erreur.

SELinux empêche Apache d’accéder au fichier index.html .

. L’étiquette par défaut devrait être httpd_sys_content_t .

. La commande restorecon permet de rétablir l’étiquette correcte.

Je vais suivre les recommandations sans toutefois les prendre au pied de la lettre, car je vais utiliser restorecon pour réétiqueter correctement tout le contenu de mon répertoire /var/www/html .

$ sudo restorecon -R -v /var/www/html/

Je recharge la page web, et je constate qu’elle s’affiche à nouveau correctement.

Modifier le contexte SELinux

Les fichiers que nous avons créés dans /var/www/html étaient tous étiquetés httpd_sys_content_t , alors que leurs copies correspondantes dans /srv/html étaient de type var_t .

En mode strict aussi bien qu’en mode permissif, chaque fichier nouvellement créé à un certain endroit du système de fichiers sera étiqueté de manière appropriée par le système. La commande matchpathcon pourra nous renseigner sur l’étiquette utilisée en fonction du répertoire.

$ matchpathcon /var/www/html/ /var/www/html system_u:object_r:httpd_sys_content_t:s0 $ matchpathcon /var/log/httpd/ /var/log/httpd system_u:object_r:httpd_log_t:s0 $ matchpathcon /etc/httpd/conf/ /etc/httpd/conf system_u:object_r:httpd_config_t:s0

La commande restorecon que nous avons utilisée un peu plus haut s’est donc chargée de restaurer le contexte par défaut des fichiers rangés dans cette arborescence.

En revanche, si nous décidons de ranger des fichiers dans un endroit un peu moins orthodoxe du système, nous devrons nous charger de définir un contexte SELinux adapté pour l’arborescence en question. Le prochain exemple nous le montrera.

Exemple pratique n° 3

Admettons que je veuille ranger les fichiers de mon serveur web dans l’arborescence /srv/web/html plutôt que dans /var/www/html .

$ sudo mkdir -pv /srv/web/html mkdir: created directory ‘/srv/web’ mkdir: created directory ‘/srv/web/html’

Comme on peut s’y attendre, le contexte SELinux par défaut de ce répertoire n’est pas adapté à son utilisation.

$ matchpathcon /srv/web/html/ /srv/web/html system_u:object_r:var_t:s0

Pour modifier le contexte par défaut de cette arborescence, je pourrais m’y prendre de la manière suivante.

$ sudo semanage fcontext -a -t httpd_sys_content_t '/srv/web(/.*)?' $ sudo restorecon -R -v /srv/web/

L’opération se fait donc en deux temps et mérite d’ailleurs quelques remarques.

Comme on s’en doute, l’outil semanage avec l’option fcontext permet de gérer les contextes de sécurité SELinux.

avec l’option permet de gérer les contextes de sécurité SELinux. L’option -a ( --add ) permet d’ajouter une entrée.

( ) permet d’ajouter une entrée. L’option -t ( --type ) spécifie le type, en l’occurrence httpd_sys_content_t .

( ) spécifie le type, en l’occurrence . L’utilisation de l’expression régulière '/srv/web(/.*)?' applique la directive récursivement sur toute l’arborescence.

applique la directive récursivement sur toute l’arborescence. Une fois que le contexte par défaut est défini, il faut l’appliquer avec restorecon .

Notons ici que la documentation de SELinux cite chcon comme premier outil pour modifier le contexte d’un fichier ou d’un répertoire. Le problème avec chcon , c’est qu’à la prochaine utilisation de restorecon sur le fichier ou ses parents, le fichier sera réétiqueté avec le contexte de son plus proche parent pour lequel un contexte spécifique est défini. Il vaut donc mieux prendre l’habitude d’utiliser semanage fcontext et restorecon pour éviter de se tirer dans le pied par la suite.

Exemple pratique n° 4

Dans ce quatrième exemple, nous mettons la pratique avant la théorie pour expliquer une autre particularité de SELinux.

Pour commencer, passez en mode permissif.

$ sudo setenforce 0

Nous allons activer l’affichage du contenu de ~/public_html pour les répertoires utilisateur. En partant de la configuration par défaut d’Apache, éditer /etc/httpd/conf.d/userdir.conf comme ceci.

<IfModule mod_userdir.c> # UserDir disabled UserDir public_html </IfModule>

En tant que simple utilisateur, créez un répertoire ~/public_html , copiez la page web par défaut dans ce répertoire en l’éditant un tant soit peu et définissez les droits d’accès qui vont bien.

$ mkdir ~/public_html $ cp -R /usr/share/httpd/noindex/* ~/public_html/ $ vim public_html/index.html (modifier le titre de la page) $ chmod 0755 public_html $ chmod 0711 ~

À partir de là, le site s’affiche à l’adresse http://amandine.microlinux.lan/~microlinux .

Repassons SELinux en mode strict.

$ sudo setenforce 1

Rafraîchissons la page, et nous nous retrouvons avec l’erreur suivante.

Les logs dans /var/log/httpd/error_log confirment qu’il s’agit d’un problème de droits d’accès, mais ne nous en disent pas plus. Jetons un oeil dans les logs de SELinux.

$ sudo sealert -a /var/log/audit/audit.log | less

La première alerte nous suggère de modifier le contexte du fichier /home/microlinux/public_html/index.html . Continuons un peu, et regardons de près la deuxième alerte.

***** Plugin catchall_boolean (32.5 confidence) suggests ***** If you want to allow httpd to enable homedirs Then you must tell SELinux about this by enabling the 'httpd_enable_homedirs' boolean. Do setsebool -P httpd_enable_homedirs 1

Gérer les booléens

Les booléens permettent de modifier une politique SELinux sans avoir à se plonger dans les arcanes de la rédaction de politiques. CentOS comporte quelques centaines de booléens, dont certains vont nous simplifier la vie.

Affichons les booléens qui concernent Apache.

$ getsebool -a | grep httpd httpd_anon_write --> off httpd_builtin_scripting --> on httpd_can_check_spam --> off httpd_can_connect_ftp --> off httpd_can_connect_ldap --> off ...

Nous pouvons en savoir un peu plus sur le rôle de chaque booléen.

$ sudo semanage boolean -l | grep httpd | sort httpd_anon_write (off, off) Allow httpd to anon write httpd_builtin_scripting (on, on) Allow httpd to builtin scripting httpd_can_check_spam (off, off) Allow httpd to can check spam httpd_can_connect_ftp (off, off) Allow httpd to can connect ftp httpd_can_connect_ldap (off, off) Allow httpd to can connect ldap

Reprenons le dernier exemple pratique et tentons de corriger la politique SELinux de manière à autoriser l’affichage du contenu de ~/public_htm l.

$ sudo setsebool -P httpd_enable_homedirs on

Notez qu’ici l’option -P rend la directive permanente, c’est-à-dire qu’elle est conservée après un redémarrage du système.

L’ensemble des booléens personnalisés apparaît dans le fichier /etc/selinux/targeted/active/booleans.local . Comme le suggère l’avertissement en tête de ce fichier, cela ne sert à rien de l’éditer directement, étant donné qu’il est automatiquement regénéré à chaque invocation de setsebool .

# This file is auto-generated by libsemanage # Do not edit directly. httpd_enable_homedirs=1

Documentation

Linux 2019 – Michael Kofler, pp. 1299 – 1306 (en allemand)

La documentation francophone du projet Fedora

Thomas Cameron – SELinux For Mere Mortals, vidéo + présentation (en anglais)

Antoine Le Morvan – Sécurisation SELinux, Formatux

La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.