Guía básica de SELinux

¿Qué es SELinux?

SELinux o Security Enhanced Linux es un software de seguridad desarrollado por la NSA, asociado al kernel de Linux que permite o deniega el acceso de las aplicaciones a ciertos servicios, como puede ser un archivo o un puerto de comunicaciones, en función de las políticas de seguridad configuradas.

SELinux es fácil de instalar pero complejo de configurar, por lo que en esta guía vamos a ver algunos conceptos básicos de funcionamiento de SELinux acompañados de ejemplos.

SELinux admite controles de acceso obligatorios y políticas de seguridad de control de acceso. Esto lo convierte en una solución de seguridad efectiva para los sistemas basados en Linux. Está disponible en muchas distribuciones de Linux y a menudo se requiere para un entorno de servidor seguro.

SELinux se basa en el concepto de un «contexto» de seguridad, que se puede asignar a cualquier cosa dentro de un sistema Linux, incluidos puertos, directorios, archivos y cuentas de usuario. También es posible asignar diferentes contextos de seguridad a diferentes tipos de objetos.

SELinux solamente impondrá las políticas de seguridad cuando se habilita, es decir, SELinux también puede arrancarse en modo permisivo, pero de esta manera no se aplica ninguna restricción. El modo permisivo es muy útil para debugar los permisos que requieren las aplicaciones antes de activar el servicio, pues los errores de acceso quedarán almacenados en el log del sistema.

El kernel y la configuración de las políticas de seguridad de SELinux deben estar configuradas correctamente. Cuando ocurren errores, un programa infectado por malware puede comprometer el sistema, causando daños graves. Al restringir el acceso de programas y procesos, SELinux limita el daño que el malware puede hacer. La política de seguridad define reglas para hacer cumplir el acceso a los recursos del sistema. También limita los privilegios de los programas del sistema.

Habilitar SELinux

SELinux viene preinstalado y habilitado por defecto, diría que, en todas las distribuciones de Linux. Lo podemos comprobar en el archivo /etc/selinux/config:

[[email protected] ~]# cat /etc/selinux/config 

# 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 three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected. 
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted


[[email protected] ~]# 

Si queremos habilitarlo o deshabilitarlo momentáneamente en caliente lo haremos mediante línea de comandos:

[[email protected] ~]# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33
[[email protected] ~]# setenforce 0
[[email protected] ~]# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   permissive
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33
[[email protected] ~]# 

Fijaos en cómo ha cambiado el valor de la directiva «current mode». Para volverlo a habilitar, utilizaremos «setenforce 1».

  Configuración de la zona horaria de un servidor Linux

Contextos de SELinux

Los contextos de SELinux son una serie de etiquetas que se utilizan en procesos y archivos de Linux para permitir o no el acceso de las aplicaciones a ellos:

[[email protected] ~]# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
root                 unconfined_u         s0-s0:c0.c1023       *
[[email protected] ~]#
  • Usuario: Las políticas de SELinux se asocian a los usuarios del sistema operativo. De esta manera, un usuario de Linux hereda las políticas de SELinux que se hayan configurado.
  • Rol: El acceso a los archivos y procesos del sistema se permitirá en función al rol asociado al usuario de SELinux.
  • Tipo: Tanto los procesos como los archivos están asociados a un dominio de SELinux. Las políticas de seguridad configuradas en SELinux define cómo se acceden los tipos entre sí (un dominio que accede a un tipo o un dominio que accede a otro dominio, por ejemplo).
  • Nivel: SELinux permite definir políticas de acceso basadas en niveles de seguridad y categorías. Por ejemplo: s0-s0:c0.c1023

Conocer el contexto al que pertenece un archivo

Con el parámetro «Z» del comando «ls» sabremos a qué contexto pertenece un archivo:

[[email protected] ~]# touch test.txt
[[email protected] ~]# ls -lZ test.txt 
-rw-r--r--. 1 root root unconfined_u:object_r:admin_home_t:s0 0 Aug  8 07:24 test.txt
[[email protected] ~]# 

Otra manera de averiguar las reglas configuradas para un archivo o un directorio, es con el comando semanage fcontext -l.

aff i?offer id=131&file id=2668&aff id=3675
[email protected] ~]# 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 
/[^/]+                                             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 
/\.ismount-test-file                               regular file       system_u:object_r:sosreport_tmp_t:s0 
/\.journal                                         all files          <<None>>
/\.snapshots(/.*)?                                 all files          system_u:object_r:snapperd_data_t:s0 
/\.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 
/bacula(/.*)?                                      all files          system_u:object_r:bacula_store_t:s0 
/bin                                               all files          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 

Restaurar las etiquetas de los contextos de todo el sistema

Si por alguna razón necesitamos restaurar los contextos de todos los archivos del sistema, el procedimiento a seguir es:

  • Configurar SELinux en modo permisivo
  • Crear el fichero touch /.autorelabel
  • Rebotar el sistema. Puede ser un proceso muy largo si tenemos muchos archivos a reetiquetar
Reinicio de Linux con autorelabel para restaurar las etiquetas de SELinux
  • Revisar los errores del sistema en /var/log/messages y /var/log/audit/audit.log.
  • Volver a configurar SELinux en modo enforcing.
  • Rebotar de nuevo
  Modificar el Keepalive en Linux RedHat

Poniendo a prueba el contexto de un archivo con SELinux

Para esta prueba he creado un fichero sencillo html que ha de cargar Apache si el contexto del archivo es el correcto.

[[email protected] html]# pwd
/var/www/html
[[email protected] html]# cat test.html 
<html>

<body>

<script type="text/javascript">
    document.write('Hello, I am ' + window.location.hostname);
</script>

</body>

</html>

[[email protected] html]# ls -lZ test.html 
-rw-r--r--. 1 root root system_u:object_r:httpd_sys_content_t:s0 140 Aug  7 07:56 test.html
[[email protected] html]# 
Apache test file

Como podemos comprobar, Apache ha podido cargar correctamente el archivo.

Ahora vamos a realizar una segunda prueba con un fichero con un contexto de SELinux no permitido. Apache no debería poder cargar el archivo.

[[email protected] ~]# ls -lZ test2.html 
-rw-r--r--. 1 root root unconfined_u:object_r:admin_home_t:s0 140 Aug  8 07:55 test2.html
[[email protected] ~]# cp -a test2.html /var/www/html/
[[email protected] ~]# ls -lZ /var/www/html/test2.html 
-rw-r--r--. 1 root root unconfined_u:object_r:admin_home_t:s0 140 Aug  8 07:55 /var/www/html/test2.html
[[email protected] ~]#

Como vemos, el contexto del fichero test2.html es admin_home_t y Apache no tiene permisos para leerlo:

Apache no puede leer un fichero con un contexto incorrecto de SELinux

En el fichero /var/log/messages, nos está avisando, justamente, de que el contexto del fichero test2.htm es incorrecto:

Aug  8 07:58:06 server1 setroubleshoot[3842]: SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/test2.html.#012#012*****  Plugin restorecon (99.5 confidence) suggests   ************************#012#012If you want to fix the label. #012/var/www/html/test2.html default label should be httpd_sys_content_t.#012Then 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.#012Do#012# /sbin/restorecon -v /var/www/html/test2.html#012#012*****  Plugin catchall (1.49 confidence) suggests   **************************#012#012If you believe that httpd should be allowed getattr access on the test2.html file by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# ausearch -c 'httpd' --raw | audit2allow -M my-httpd#012# semodule -X 300 -i my-httpd.pp#012

Por lo tanto, lo que tenemos que hacer es modificar el contexto del fichero test2.html. Lo haremos de la siguiente manera:

[[email protected] ~]# /sbin/restorecon -v /var/www/html/test2.html
Relabeled /var/www/html/test2.html from unconfined_u:object_r:admin_home_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
[[email protected] ~]# ls -lZ /var/www/html/test2.html 
-rw-r--r--. 1 root root unconfined_u:object_r:httpd_sys_content_t:s0 140 Aug  8 07:55 /var/www/html/test2.html
[[email protected] ~]# 

Ahora ya sí que deja cargar el fichero.

Lo que hace el comando restorecon ejecutado anteriomente, es revisar cuál es la regla de SELinux configurada para el directoro /var/www/html y aplicársela al archivo test2.html, ya que es una regla recursiva.

[[email protected] ~]# semanage fcontext -l |grep "/var/www/html"
/var/www/html(/.*)?/sites/default/files(/.*)?      all files          system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/html(/.*)?/sites/default/settings\.php    regular file       system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/html(/.*)?/uploads(/.*)?                  all files          system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/html(/.*)?/wp-content(/.*)?               all files          system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/html(/.*)?/wp_backups(/.*)?               all files          system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/html/[^/]*/cgi-bin(/.*)?                  all files          system_u:object_r:httpd_sys_script_exec_t:s0 
/var/www/html/cgi/munin.*                          all files          system_u:object_r:munin_script_exec_t:s0 
/var/www/html/configuration\.php                   all files          system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/html/munin(/.*)?                          all files          system_u:object_r:munin_content_t:s0 
/var/www/html/munin/cgi(/.*)?                      all files          system_u:object_r:munin_script_exec_t:s0 
/var/www/html/nextcloud/data(/.*)?                 all files          system_u:object_r:httpd_sys_rw_content_t:s0 
/var/www/html/owncloud/data(/.*)?                  all files          system_u:object_r:httpd_sys_rw_content_t:s0 
[[email protected] ~]# 

Aplicar una regla nueva de contexto de SELinux a un directorio nuevo

Pongamos por caso que tenemos un nuevo servicio de Apache en /apache2 pero no hay ninguna regla de SELinux aplicada todavía y, por lo tanto, Apache no podrá leer el archivo.

  Convertir una imagen de OVA a VHD con VirtualBox

Lo que tendremos que hacer es añadir una regla nueva de SELinux al nuevo directoro. Veámos cómo se hace:

  • Creamos el directorio nuevo y un archivo de pruebas que deberá leer apache:
[[email protected] ~]# mkdir /apache2
[[email protected] ~]# cd /apache2/
[[email protected] apache2]# touch test > test.txt
[[email protected] apache2]# ls -lZ
total 0
-rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Aug  8 08:25 test
-rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Aug  8 08:25 test.txt
[[email protected] apache2]# 
  • Creamos una nueva regla de SELinux para que Apache pueda leer el directorio /apache2 de manera recursiva:
[[email protected] ~]# semanage fcontext -a -t httpd_sys_content_t "/apache2(/.*)?"
[[email protected] ~]# restorecon -R -v /apache2
Relabeled /apache2 from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
Relabeled /apache2/test.txt from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
Relabeled /apache2/test from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
[[email protected] ~]# 

Podemos comprobar que la etiqueta del ficheros de /apache2 ha cambiado:

[[email protected] ~]# ls -lZ /apache2/
total 0
-rw-r--r--. 1 root root unconfined_u:object_r:httpd_sys_content_t:s0 0 Aug  8 08:25 test
-rw-r--r--. 1 root root unconfined_u:object_r:httpd_sys_content_t:s0 0 Aug  8 08:25 test.txt
[[email protected] ~]# 

Si quisiéramos eliminar la regla de SELinux que hemos configurado previamente para el directorio /apache2, lo haríamos con el parámetro «-d» (delete) de semanage:

[[email protected] ~]# semanage fcontext -d "/apache2(/.*)?"

Puedes consultar más ejemplos con: man semanage-fcontext

Aplicando reglas de SELinux a puertos de comunicaciones

Anteriormente comentaba que las reglas de SELinux no solamente se aplican a ficheros, si no también a procesos. Pongamos por caso que queremos arrancar Apache por un puerto personalizado. Pongamos por caso, el 82. Si no hay una regla definida en SELinux para asociar el puerto 82 a Apache, el servicio no arrancará.

Aug 08 08:50:41 server1 httpd[4918]: (13)Permission denied: AH00072: make_sock: could not bind to address [::]:82
Aug 08 08:50:41 server1 httpd[4918]: (13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:82

Para habilitar esta nueva regla, también utilizaremos semanage con el parámetro port:

[[email protected] conf]# semanage port -a -t http_port_t -p tcp 82
[[email protected] conf]# semanage port -l |grep http_port
http_port_t                    tcp      82, 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t            tcp      5988
[[email protected] conf]# 

Puedes consultar más ejemplos con: man semanage-port.

Te puede interesar

COMPÁRTEME

Deja un comentario