howtos/Linux/selinux guia basica.txt

217 lines
14 KiB
Plaintext

¿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 complejo, por lo que en esta guía vamos a ver algunos conceptos básicos de funcionamiento de SELinux acompañados de ejemplos.
Haz clic para aceptar las cookies de márketing y permitir este contenido
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:
[root@server1 ~]# 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
[root@server1 ~]#
Si queremos habilitarlo o deshabilitarlo momentáneamente en caliente lo haremos mediante línea de comandos:
[root@server1 ~]# 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
[root@server1 ~]# setenforce 0
[root@server1 ~]# 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
[root@server1 ~]#
Fijaos en cómo ha cambiado el valor de la directiva «current mode». Para volverlo a habilitar, utilizaremos «setenforce 1».
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:
[root@server1 ~]# 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 *
[root@server1 ~]#
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
LEER Configuración de un Proxy por defecto en Linux RedHat
Conocer el contexto al que pertenece un archivo
Con el parámetro «Z» del comando «ls» sabremos a qué contexto pertenece un archivo:
[root@server1 ~]# touch test.txt
[root@server1 ~]# 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
[root@server1 ~]#
Otra manera de averiguar las reglas configuradas para un archivo o un directorio, es con el comando semanage fcontext -l.
root@server1 ~]# 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
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.
[root@server1 html]# pwd
/var/www/html
[root@server1 html]# cat test.html
<html>
<body>
<script type="text/javascript">
document.write('Hello, I am ' + window.location.hostname);
</script>
</body>
</html>
[root@server1 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
[root@server1 html]#
Apache test file
Como podemos comprobar, Apache ha podido cargar correctamente el archivo.
LEER Modificar el Keepalive en Linux RedHat
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.
[root@server1 ~]# 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
[root@server1 ~]# cp -a test2.html /var/www/html/
[root@server1 ~]# 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
[root@server1 ~]#
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:
[root@server1 ~]# /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
[root@server1 ~]# 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
[root@server1 ~]#
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.
[root@server1 ~]# 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
[root@server1 ~]#
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.
LEER Comandos básicos de Linux relacionados con los procesos
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:
[root@server1 ~]# mkdir /apache2
[root@server1 ~]# cd /apache2/
[root@server1 apache2]# touch test > test.txt
[root@server1 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
[root@server1 apache2]#
Creamos una nueva regla de SELinux para que Apache pueda leer el directorio /apache2 de manera recursiva:
[root@server1 ~]# semanage fcontext -a -t httpd_sys_content_t "/apache2(/.*)?"
[root@server1 ~]# 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
[root@server1 ~]#
Podemos comprobar que la etiqueta del ficheros de /apache2 ha cambiado:
[root@server1 ~]# 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
[root@server1 ~]#
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:
[root@server1 ~]# 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:
[root@server1 conf]# semanage port -a -t http_port_t -p tcp 82
[root@server1 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
[root@server1 conf]#
Puedes consultar más ejemplos con: man semanage-port.