Sécuriser son architecture avec SELinux

From Deimos.fr / Bloc Notes Informatique
Jump to: navigation, search

1 Introduction

Security-Enhanced Linux, abrégé SELinux, est un LSM (Linux security module), qui permet de définir une politique d'accès MAC (mandatory access control) aux éléments d'un système basé sur Linux. Initié par la NSA sur la base de travaux menés avec SCC et l'université d'Utah aux USA (prototypes DTMach, DTOS, projet FLASK), son architecture dissocie l'application de la politique d'accès et sa définition. Il permet notamment de classer les applications d'un système, en différents groupes, avec des niveaux d'accès plus fins. Il permet aussi d'attribuer un niveau de confidentialité pour l'accès à des objets systèmes, comme des descripteurs de fichier, selon un modèle de sécurité multi-niveaux MLS (Multi level Security). SELinux utilise le modèle Bell LaPadula avec Type enforcement de SCC pour l'intégrité. Il s'agit d'un logiciel libre, certaines parties étant sous licences GNU GPL ou BSD.

En pratique, la base de l'innovation est de définir des attributs étendus dans le système de fichiers UNIX. En plus de la notion de "droits de lecture, écriture, exécution" pour un usager donné, SELinux définit pour chaque fichier ou processus :

  • Un usager virtuel (ou collection de rôles) ;
  • Un rôle ;
  • Un contexte de sécurité.

2 Utilisation

2.1 Définir le mode

C'est ici que vous définissez le mode SELinux, ainsi que son type. Nous utiliserons ici le mode targeted qui est le mode mono utilisateur (personne au dessus de root). Le mode mls étant équivalent au RBAC qui permet d'avoir beaucoup plus de groupes et d'utilisateur sécurité (pour les très grosses compagnies) :

Configuration File /etc/sysconfig/selinux
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

2.2 Obtenir le mode actuel et en changer

Nous avons dans un premier temps besoin de savoir dans quel mode nous sommes :

Command getenforce
$ getenforce 
Enforcing

Nous voyons ici que je suis en mode enforcing. Si je veux passer en mode permissive, je lance cette commande avec l'argument 0 :

Command setenforce
setenforce 0

Et je le passe à 1 pour revenir en mode enforcing.

Nous pouvons vérifier que SELinux est bien activer en listant les process. Les attributs SELinux se montreront avec l'argument 'Z' :

Command ps
$ ps axZ | grep cron
system_u:system_r:crond_t:s0-s0:c0.c1023 1417 ? Ss    0:00 crond
system_u:system_r:crond_t:s0-s0:c0.c1023 1428 ? Ss    0:00 /usr/sbin/atd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2082 pts/0 S+   0:00 grep cron

Nous pouvons également le faire sur des dossiers ou fichiers :

Command ls
$ ls -Z /root
-rw-------. root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 install.log
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 install.log.syslog

2.2.1 Désactiver un domaine uniquement

Vous avez également le choix de ne désactiver qu'un domaine si vous le souhaitez. Nous allons prendre par exemple Apache :

Command semanage
semanage permissive -a httpd_t

Ce service est donc maintenant en état permissive :

2.3 Analyser les bloquages

Lorsque SELinux décide de bloquer certains accès, il existe plusieurs possibilité pour analyser et accepter certains faux positifs. Dans un premier temps, il y a la commande 'audit2allow' :

Command audit2allow
 audit2allow -la
 
 
#============= httpd_t ==============
allow httpd_t admin_home_t:file { read getattr open };

Vous avez également les logs qui vous renseigne sur les bloquages dans /var/log/audit/autit.log :

Configuration File /var/log/audit/autit.log
type=AVC msg=audit(1317855069.699:15772): avc:  denied  { getattr } for  pid=2273 comm="httpd" path="/var/www/html/mon_fichier.txt" dev=dm-0 ino=30073 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
type=SYSCALL msg=audit(1317855069.699:15772): arch=c000003e syscall=4 success=yes exit=0 a0=7f300213e3c8 a1=7ffffd59c590 a2=7ffffd59c590 a3=0 items=0 ppid=2268 pid=2273 auid=0 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=2 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1317855069.700:15773): avc:  denied  { read } for  pid=2273 comm="httpd" name="mon_fichier.txt" dev=dm-0 ino=30073 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
type=AVC msg=audit(1317855069.700:15773): avc:  denied  { open } for  pid=2273 comm="httpd" name="mon_fichier.txt" dev=dm-0 ino=30073 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
type=SYSCALL msg=audit(1317855069.700:15773): arch=c000003e syscall=2 success=yes exit=11 a0=7f300213e480 a1=80000 a2=0 a3=2 items=0 ppid=2268 pid=2273 auid=0 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=2 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)

Je peux voir ici qu'un fichier nommé mon_fichier.txt a été interdit sur httpd_t du fait que l'objet ne soit pas bon.

2.4 Les contextes

Vous avez pu le voir, il y a des attributs un peu particuliers que l'on appelle les contextes. On peut afficher cette liste de contextes va la commande 'semanage' qui nous permet de gérer les contextes :

Command semanage
$ semanage fcontext -l | more
SELinux fcontext                                   type               Context
 
/                                                  directory          system_u:object_r:root_t:s0 
/.*                                                all files          system_u:object_r:default_t:s0 
/HOME_DIR/\.Xdefaults                              all files          system_u:object_r:config_home_t:s0 
/HOME_DIR/\.xine(/.*)?                             all files          system_u:object_r:config_home_t:s0 
/[^/]+                                             regular file       system_u:object_r:etc_runtime_t:s0 
/\.autofsck                                        regular file       system_u:object_r:etc_runtime_t:s0 
/\.autorelabel                                     regular file       system_u:object_r:etc_runtime_t:s0 
/\.journal                                         all files          <<None>>
/\.suspended                                       regular file       system_u:object_r:etc_runtime_t:s0 
/a?quota\.(user|group)                             regular file       system_u:object_r:quota_db_t:s0 
/afs                                               directory          system_u:object_r:mnt_t:s0 
/bin                                               directory          system_u:object_r:bin_t:s0 
/bin/.*                                            all files          system_u:object_r:bin_t:s0 
/bin/alsaunmute                                    regular file       system_u:object_r:alsa_exec_t:s0 
/bin/bash                                          regular file       system_u:object_r:shell_exec_t:s0 
/bin/bash2                                         regular file       system_u:object_r:shell_exec_t:s0 
/bin/d?ash                                         regular file       system_u:object_r:shell_exec_t:s0 
/bin/dbus-daemon                                   regular file       system_u:object_r:dbusd_exec_t:s0 
/bin/dmesg                                         regular file       system_u:object_r:dmesg_exec_t:s0 
/bin/fish                                          regular file       system_u:object_r:shell_exec_t:s0 
/bin/fusermount                                    regular file       system_u:object_r:fusermount_exec_t:s0
...

Les contexts matchent des regex et sont autorisés de cette manière.

2.4.1 Modification des contexts

Admettons que pour mon site web, je souhaites créer un index. Je me trouve dans /tmp et créer mon index. A ce moment là, à la création du fichier sur le disque, SELinux va tagger le fichier index et lui spécifier qu'il appartient au dossier /tmp.
Donc lorsque je vais le déplacer dans /var/www, il va toujours garder ces attributs et le serveur apache ne pourra utiliser ce fichier. Pour corriger le problème, 2 choix s'offrent à moi :

  • Restaurer les droits qui sont définit dans la base de contexts pour le dossier parent.
  • Réattribuer les bons droits sur le fichier en question

2.4.1.1 Restauration des contexts

Pour restaurer les contexts, nous allons utiliser la commande restcon :

Command restcon
restcon -Rv /var/www

Et là nous venons de réinitialiser tous les droits SELinux dans /var/www.

2.4.1.2 Réattribution des contexts

Pour lui réattribuer les bons droits, il va falloir que je relance la politique de sécurité sur ce fichier :

Command chcon
chcon -v -t httpd_sys_content_t /var/www/index.html

httpd_sys_content_t : ceci est le type de context désiré pour le dossier /var/www

Pour trouver le bon context, il faut utiliser la commande semanage comme vu plus haut :

Command semanage
$ semanage fcontext -l | grep "/var/www"
/var/www(/.*)?                                     all files          system_u:object_r:httpd_sys_content_t:s0 
/var/www(/.*)?/logs(/.*)?                          all files          system_u:object_r:httpd_log_t:s0 
/var/www/[^/]*/cgi-bin(/.*)?                       all files          system_u:object_r:httpd_sys_script_exec_t:s0 
...

Vous pouvez voir sur la dernière colonne que le context recherché est "httpd_sys_content_t".

2.4.1.3 Ajout d'un context

Voici une chose qu'il faut éviter de faire pour résoudre des problèmes, mais plutôt à utiliser pour améliorer la sécurité ou la customiser pour ses besoins. Nous allons donc ici ajouter un context pour résoudre le problème de fichier listé plus haut qui appartient à admin et qui se trouve dans /var/www/html. Nous allons donc rajouter un context avec les droits du dossier root :

Command semanage
semanage fcontext -a -t admin_home_t "/var/www(/.*)?"

Ensuite vous pouvez vérifier vos changements :

Command semanage
$ semanage fcontext -l | grep www
/srv/([^/]*/)?www(/.*)?                            all files          system_u:object_r:httpd_sys_content_t:s0 
/usr/share/awstats/wwwroot(/.*)?                   all files          system_u:object_r:httpd_awstats_content_t:s0 
/usr/share/awstats/wwwroot/cgi-bin(/.*)?           all files          system_u:object_r:httpd_awstats_script_exec_t:s0 
/var/www(/.*)?                                     all files          system_u:object_r:admin_home_t:s0

Il ne vous reste plus qu'à faire un "restcon" pour réparer les permissions

2.4.2 Bloquage par port

SELinux autorise également que certains services à ne tourner que sur certains ports. La preuve :

Command semanage
$ semanage port -l | grep http
http_cache_port_t              tcp      3128, 8080, 8118, 10001-10010
http_cache_port_t              udp      3130
http_port_t                    tcp      80, 443, 488, 8008, 8009, 8443
pegasus_http_port_t            tcp      5988
pegasus_https_port_t           tcp      5989

Si vous souhaitez par exemple faire tourner apache sur un autre port, il va falloir le rajouter dans la liste des contexts :

Command semanage
semanage port -a -t http_port_t -p tcp 81

J'ai choisis ici le port 81.

2.5 Les Booléens

Les booléens sont une autre sorte de bloquage que SELinux pratique et cela se trouve généralement sur des services bien connu. Pour obtenir cette liste :

Command getsebool
$ getsebool -a
abrt_anon_write --> off
allow_console_login --> on
allow_corosync_rw_tmpfs --> off
allow_cvs_read_shadow --> off
allow_daemons_dump_core --> on
allow_daemons_use_tty --> on
allow_domain_fd_use --> on
allow_execheap --> off
allow_execmem --> on
allow_execmod --> on
allow_execstack --> on
allow_ftpd_anon_write --> off
allow_ftpd_full_access --> off
allow_ftpd_use_cifs --> off
...

Pour modifier une valeur, il suffit de faire :

Command allow_ftpd_full_access
setsebool allow_ftpd_full_access on

Vous pouvez vérifier ensuite de 2 manières :

Command
$ getsebool allow_ftpd_full_access

ou

$ semanage boolean -l 

3 FAQ

3.1 Mon système refuse de booter à cause de SELinux

Pour corriger ce problème, au boot du grub, éditez la ligne du kernel et ajoutez ceci à la fin :

enforcing=0

Cela mettra en permissive au boot de la machine pour que vous puissiez corriger votre problème.

3.2 Comment rappliquer toutes les politiques de sécurité à mon système ?

Si vous souhaitez réinitialiser toute votre politique de sécurité SELinux sur votre machine, il y a 2 solutions. La première est la plus sale, elle consiste vérifier et à rappliquer tous les changement à chaud :

Command
restorecon -R /

Je vous l'avais dit... c'est moche ! Par contre une autre solution plus propre qui rappliquera correctement toutes les permissions au prochain reboot est de créer un fichier à la racine :

Command touch
touch /autorelabel

3.3 J'ai un problème selinux et rien dans mes logs

J'ai eu le cas avec un samba qui me posait problème et dont ni audit2allow, ni les logs ne voyaient quelque chose. Pour résoudre ce problème et voir les messages de log, dites lui de tout logger :

Command semanage
semanage dontaudit off

Ensuite il ne vous reste plus qu'à regarder dans les logs (/var/log/audit/audit.log et /var/log/messages).

4 Ressources

SELinux, l’agence de sécurité du noyau