Introducción a las configuraciones básicas en SELinux

Última actualización: 17/12/2025
Autor: Isaac
  • SELinux añade una capa de control de acceso obligatorio basada en contextos y tipos para reforzar la seguridad de Linux más allá de los permisos tradicionales.
  • La administración cotidiana se centra en modos (enforcing, permissive), etiquetado correcto, booleans y herramientas como semanage, semodule y restorecon.
  • Los registros en /var/log/audit/audit.log, junto con audit2why y audit2allow, permiten diagnosticar problemas y, si es necesario, crear políticas locales específicas.
  • El desarrollo de módulos personalizados y el uso de políticas modulares facilitan adaptar SELinux a aplicaciones propias sin sacrificar un modelo de seguridad fino.

Conceptos basicos de SELinux

Si administras sistemas Linux y te preocupa la seguridad, tarde o temprano vas a cruzarte con SELinux. Aunque a veces tiene fama de «romper cosas», en realidad es una capa de protección muy potente que limita qué puede hacer cada proceso en el sistema, incluso cuando ya ha pasado los permisos tradicionales de Unix.

A lo largo de esta guía vamos a ver, con bastante detalle y con un lenguaje lo más claro posible, cómo funciona SELinux por dentro, qué son sus contextos, políticas, modos de operación y herramientas básicas de administración, y cómo empezar a usarlo con cabeza sin morir en el intento, tanto en distribuciones tipo Red Hat como en Debian o SUSE.

Qué es SELinux y cómo encaja en la seguridad de Linux

SELinux (Security-Enhanced Linux) es un sistema de control de acceso obligatorio (MAC) que se integra en el kernel de Linux mediante la interfaz LSM (Linux Security Modules). Mientras que el control de acceso discrecional (DAC) clásico se basa en usuarios, grupos y permisos de lectura/escritura/ejecución, SELinux añade una capa extra que responde a la pregunta: «¿Puede este sujeto hacer esta acción sobre este objeto?».

Con DAC, el dueño de un archivo tiene bastante libertad para cambiar permisos y, en la práctica, un proceso que comprometa una cuenta puede llegar a acceder a muchos más recursos de los que debería. SELinux, en cambio, impone una política centralizada: aunque el sistema de permisos tradicional permita un acceso, si la política de SELinux no lo autoriza, se bloquea. Las reglas de SELinux se evalúan después de las de DAC, así que si DAC ya deniega algo, SELinux ni siquiera entra en juego.

En la práctica, el núcleo del sistema consulta a SELinux antes de autorizar cada llamada al sistema relevante, para decidir si el proceso involucrado está autorizado a realizar la operación sobre el recurso concreto según la política cargada. Esa política es un gran conjunto de reglas que describen qué procesos pueden interactuar con qué ficheros, directorios, sockets, puertos y otros objetos.

SELinux responde a esta pregunta de autorización usando un concepto clave: el contexto de seguridad. Tanto procesos como objetos (archivos, directorios, puertos, etc.) llevan asociada una etiqueta especial, el contexto SELinux, que abstrae detalles de bajo nivel y se centra en sus propiedades de seguridad. Esto evita ambigüedades típicas, por ejemplo, cuando un mismo archivo es accesible mediante distintos caminos debido a montajes bind.

Contextos de SELinux: usuario, rol, tipo y nivel

Un contexto de SELinux suele representarse como una cadena con varios campos: usuario SELinux, rol SELinux, tipo y nivel de seguridad. Aunque todos los campos son relevantes, en la práctica la parte más importante para la mayoría de políticas es el tipo, porque las reglas de acceso más habituales se definen entre tipos.

Los tipos de SELinux se reconocen fácilmente porque terminan en _t. Por ejemplo, el proceso del servidor web Apache se ejecuta normalmente con el tipo httpd_t, los archivos que publica el servidor web en /var/www/html/ suelen estar etiquetados con httpd_sys_content_t, los ficheros temporales de /tmp y /var/tmp/ suelen ser tmp_t, y los puertos que pueden usar los servidores web se marcan como http_port_t. La política define qué combinaciones de tipos se permiten o se prohíben.

Gracias a esto, aunque Apache se vea comprometido, SELinux puede impedir que ese proceso bajo httpd_t acceda, por ejemplo, a los datos de MariaDB. Si no existe ninguna regla que permita a httpd_t acceder a objetos etiquetados como mysqld_db_t (típicos de /data/mysql/), ese acceso será denegado incluso si el sistema de permisos Unix lo permitiría.

El contexto de un proceso no depende solo del ejecutable, sino también del usuario SELinux, rol y dominio que tenga en ese momento. El dominio es, de hecho, el tipo asociado al proceso (por ejemplo, ssh_t para el daemon SSH), y es el dominio el que determina qué puede y qué no puede hacer ese proceso. Los roles controlan qué dominios puede adoptar un usuario y cómo puede cambiar entre ellos.

Cuando un usuario inicia sesión, se le asigna un contexto SELinux predeterminado que fija su identidad SELinux, el rol inicial y el dominio de los procesos que lance. Si quiere cambiar de rol (y, normalmente, de dominio asociado) debe usar el comando newrole -r rol_r -t dominio_t, que pedirá la contraseña para evitar que programas cambien de rol de forma automática. Solo si la política lo permite expresamente podrán darse esas transiciones.

Estados y modos de funcionamiento de SELinux

SELinux puede estar globalmente activado o desactivado, y cuando está activo funciona en uno de varios modos. Es importante distinguir entre estado (habilitado o deshabilitado) y modo (cómo se aplican las políticas cuando está habilitado).

Cuando SELinux está habilitado en el kernel, puede operar en estos tres modos principales:

  • Enforcing (modo de aplicación): SELinux aplica estrictamente la política cargada. Si una acción viola una regla, la operación se bloquea y se registra un mensaje en los registros de auditoría. Es el modo más seguro y el recomendado una vez que el sistema está bien configurado.
  • Permissive (modo permisivo): la política se evalúa, pero las violaciones no se bloquean; simplemente se registran en /var/log/audit/audit.log. Este modo es ideal para pruebas, depuración y para preparar la migración a enforcing sin romper servicios.
  • Disabled (deshabilitado): SELinux está completamente apagado; ni aplica reglas ni registra incidentes. En este estado no hay protección adicional de SELinux.
  La constelación satelital IRIS2 de la Unión Europea: Soberanía digital y competitividad en el espacio

En sistemas tipo Red Hat o similares, el modo actual se puede consultar con getenforce, que devuelve Enforcing, Permissive o Disabled. Para cambiar dinámicamente entre enforcing y permissive sin reiniciar se usa setenforce 0 (permissive) o setenforce 1 (enforcing), siempre que en el archivo de configuración no esté deshabilitado por completo.

Para configurar el comportamiento persistente tras un reinicio se edita el archivo /etc/selinux/config, asegurando que la línea SELINUX=enforcing, SELINUX=permissive o SELINUX=disabled refleje lo que queremos. Si se cambia a disabled, SELinux deja de cargarse al arrancar el sistema y no puede cambiarse solo con setenforce.

En entornos Debian, además de estos modos, se pueden pasar parámetros al kernel como selinux=1 security=selinux para habilitarlo, audit=1 para forzar el registro de las operaciones denegadas y enforcing=1 para arrancar directamente aplicando la política. Estos parámetros se añaden en la línea de kernel de GRUB, normalmente modificando GRUB_CMDLINE_LINUX en /etc/default/grub y ejecutando update-grub.

Instalación y activación básica de SELinux

En la mayoría de distribuciones modernas, el kernel ya viene con soporte SELinux integrado y las herramientas de usuario están disponibles en paquetes específicos. Si necesitas ajustar la configuración del kernel, consulta cómo buscar configuraciones en make menuconfig. Aun así, la forma de habilitarlo y configurarlo cambia ligeramente según la familia de la distribución, aunque la idea de fondo siempre es la misma: instalar las políticas, etiquetar el sistema de archivos y arrancar el kernel con SELinux activado.

En Debian, por ejemplo, el comando apt install selinux-basics selinux-policy-default auditd instala automáticamente los componentes necesarios para usar SELinux. El paquete selinux-policy-default incluye una política estándar modular, que por defecto solo restringe ciertos servicios expuestos y deja a los usuarios en una especie de dominio sin restricciones (módulo unconfined). Si se quiere una política más parecida a la antigua «strict» hay que deshabilitar ese módulo.

Tras instalar una política es obligatorio etiquetar todos los archivos del sistema, es decir, asignarles un tipo SELinux adecuado según las reglas de etiquetado. En Debian esto puede hacerse con fixfiles relabel, que recorre el sistema y aplica las etiquetas según la política instalada. Este proceso puede tardar bastante tiempo, sobre todo en máquinas con muchos datos.

Hay un script, selinux-activate, que automatiza gran parte de este proceso en Debian: ajusta parámetros de arranque, prepara el etiquetado y fuerza un relabel en el siguiente reinicio, evitando que se creen archivos sin etiquetar mientras SELinux todavía no está plenamente en marcha.

En entornos Red Hat y derivados, cuando se habilita SELinux por primera vez suele hacerse algo parecido: se ajusta /etc/selinux/config a SELINUX=permissive, se crea el archivo vacío /.autorelabel y se reinicia el sistema (por ejemplo, con init 6). El archivo /.autorelabel indica al sistema que debe re-etiquetar todo el sistema de archivos en el arranque siguiente. Una vez completado, se puede pasar a modo enforcing tanto en el archivo de configuración como con setenforce 1.

Políticas SELinux: tipos, módulos y administración

La política de SELinux es, en esencia, un gran conjunto de reglas que determinan cómo pueden interactuar procesos y objetos en el sistema. Sin embargo, no se mantiene como un único fichero monolítico, sino de forma modular, mediante paquetes de política que pueden activarse o desactivarse según los servicios instalados.

En Debian, por ejemplo, los módulos de política disponibles se encuentran en /usr/share/selinux/default/, y la configuración activa se almacena en /etc/selinux/default/. Aunque estos ficheros sean legibles, no se deben editar a mano: siempre hay que usar las herramientas pensadas para gestionarlos, como semodule y semanage.

El comando semodule se utiliza para gestionar los módulos de política instalados. Entre sus opciones básicas están:

  • semodule -i modulo.pp.bz2: instala un módulo de política (comprimido con bzip2) en la configuración actual.
  • semodule -r nombre_modulo: elimina un módulo ya instalado.
  • semodule -l: lista los módulos presentes, con sus versiones.
  • semodule -e nombre_modulo y semodule -d nombre_modulo: activan o desactivan selectivamente módulos sin desinstalarlos.

Por defecto, semodule aplica los cambios sobre la política seleccionada por la variable SELINUXTYPE en /etc/selinux/config. Es posible trabajar sobre otro tipo de política usando la opción -s. Los cambios son inmediatos salvo que se use la opción -n, que evita recargar la política en caliente.

Por otro lado está semanage, la navaja suiza para ajustar la configuración de alto nivel de SELinux: mapea usuarios del sistema con identidades SELinux, gestiona reglas de etiquetado de ficheros y puertos, modifica booleans, etc. Cada tipo de dato gestionado por semanage tiene su propia página de manual, como semanage-login(8) o semanage-user(8), y la sintaxis de las subórdenes es bastante coherente: -a para añadir, -d para borrar, -m para modificar, -l para listar y -t para indicar un tipo o dominio.

  Los mejores buscadores para Deep Web y cómo usarlos con seguridad

Con semanage login -l se obtienen las correspondencias actuales entre nombres de usuarios y usuarios SELinux. Los usuarios no listados explícitamente heredan la identidad por defecto, representada como __default__. Por ejemplo, semanage login -a -s user_u usuario asigna la identidad SELinux user_u a ese usuario Unix, y semanage login -d usuario revierte esa asignación.

El comando semanage user -l muestra las asociaciones entre identidades SELinux (como user_u, staff_u, sysadm_u) y los roles que se les permiten. Al crear una nueva identidad SELinux hay que indicar los roles que podrá adoptar y un prefijo de etiquetado (user, staff o sysadm) que determina el tipo de los archivos personales, por ejemplo staff_home_dir_t para usuarios con prefijo staff. Una orden típica sería semanage user -a -R 'staff_r user_r' -P staff test_u, que crea un usuario SELinux test_u con ciertos roles y un esquema de etiquetado concreto.

Etiquetado de archivos, directorios y puertos

Una vez instalada la política, cada archivo, directorio, dispositivo, socket o puerto relevante del sistema debe tener un tipo SELinux coherente con su función. Esa asociación entre rutas/puertos y tipos se conoce como reglas de contextos de fichero (file contexts) o reglas de etiquetado.

Para ficheros y directorios, las etiquetas SELinux se almacenan como atributos extendidos del sistema de archivos. Se pueden ver fácilmente con ls -Z, por ejemplo ls -Z /etc/httpd. Para procesos y puertos, el kernel es quien mantiene el contexto, y se puede inspeccionar con comandos como ps auxZ | grep httpd para procesos o netstat -anpZ | grep httpd para ver puertos etiquetados.

Si queremos saber qué contexto se aplica por defecto a los ficheros bajo /var/www/html, podemos usar ls -Z /var/www/html o semanage fcontext -l | grep '/var/www'. Lo habitual es encontrar algo como httpd_sys_content_t para los contenidos servidos por Apache. En cambio, un directorio doméstico como /home/dan/html puede tener algo tipo user_home_t, que impedirá que el servidor web acceda a él aunque DAC lo permita.

Para permitir que el servidor web lea contenidos desde /home/dan/html de forma alineada con SELinux, habría que decirle a la política que a esos ficheros se les debe aplicar el tipo httpd_sys_content_t. Esto se hace registrando una regla de etiquetado con semanage fcontext -a -t httpd_sys_content_t '/home/dan/html(/.*)?' y, a continuación, ejecutando restorecon -Rv /home/dan/html para aplicar el nuevo contexto a los ficheros existentes.

El patrón '/home/dan/html(/.*)?' es una expresión regular que indica que se aplica tanto al directorio como a todo su contenido recursivo. restorecon se encarga de sincronizar las etiquetas reales del sistema de archivos con las reglas guardadas en la política, algo que también se usa tras grandes cambios o restauraciones de copias de seguridad.

De forma similar, los puertos TCP/UDP también tienen un tipo SELinux. El servidor web, por ejemplo, usa puertos etiquetados como http_port_t. Si queremos que Apache escuche en el puerto 8080, además de configurarlo en el propio servidor web, debemos registrar el puerto con semanage port -m -t http_port_t -p tcp 8080 para que SELinux lo considere un puerto válido para ese servicio.

Booleans de SELinux: interruptores de comportamiento

Además de reglas estáticas, muchas políticas SELinux exponen opciones booleanas (booleans) que permiten activar o desactivar determinadas partes del comportamiento sin recompilar ni cargar módulos nuevos. Son muy útiles para ajustar permisos a necesidades reales sin complicarse con políticas personalizadas.

Podemos ver todas las opciones disponibles con getsebool -a, que lista el nombre de cada booleano y su valor actual (on/off). Si queremos algo más detallado, incluyendo una descripción, se puede usar semanage boolean -l, y filtrar por palabras clave con grep para localizar lo que nos interesa, por ejemplo ftp o httpd.

Imagina que queremos que un servidor FTP tenga permiso de lectura y escritura en los directorios personales de los usuarios y, aunque todo parece bien configurado a nivel de sistema, no se ven los archivos. Revisando con semanage boolean -l | grep ftp podemos encontrar un booleano llamado ftp_home_dir con descripción «Allow ftp to read & write file in user home directory» y valor off. Activarlo con setsebool ftp_home_dir on hace que el servidor FTP pueda acceder a esos directorios de acuerdo con la política.

Otro ejemplo típico es el booleano httpd_enable_homedirs, que permite al servidor web acceder a directorios personales para servir sitios como ~/public_html/. Podemos comprobar su valor con getsebool httpd_enable_homedirs, y si aparece en off, habilitarlo definitivamente con setsebool -P httpd_enable_homedirs on. La opción -P asegura que el cambio se guarda de forma persistente y sobrevive a los reinicios.

En general, antes de lanzarse a escribir políticas complejas, merece la pena revisar cuidadosamente los booleans relacionados con el servicio que estamos ajustando. Muchas veces, una simple opción on/off resuelve lo que parece un problema grave de permisos.

Diagnóstico: registros, audit2why y audit2allow

Cuando SELinux deniega una operación, genera un evento de control de acceso (AVC) que se registra en /var/log/audit/audit.log (si el servicio auditd está activo y audit=1 está configurado). De cara a la administración diaria, aprender a leer esos mensajes es fundamental para entender por qué se ha bloqueado algo.

Un mensaje típico de AVC puede tener este aspecto: avc: denied { read write } for pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file permissive=1. En él se indica qué permisos se han denegado, qué proceso está implicado (PID, comando y contexto de origen) y contra qué objeto (nombre, tipo y clase de objeto). Con esa información es posible redactar una regla que autorice expresamente esa operación, por ejemplo allow syslogd_t device_t:fifo_file { read write }.

Analizar el log a mano es incómodo, así que existen herramientas específicas como ausearch para buscar eventos de interés y, sobre todo, audit2why y audit2allow para interpretar lo que está pasando. Con audit2why < /var/log/audit/audit.log podemos obtener un resumen de las causas de las denegaciones, lo que ayuda mucho a identificar configuraciones erróneas o booleans que faltan por activar.

  Cómo desactivar el uso compartido en proximidad en Windows 11 paso a paso

Si a pesar de ajustar booleans y contextos seguimos viendo errores repetidos para un mismo servicio, podemos plantearnos crear una política local específica para ese caso. Por ejemplo, para compilar reglas que permitan los accesos actualmente denegados a Apache podemos hacer algo como grep httpd_t /var/log/audit/audit.log | audit2allow -M http_policy, que genera un módulo de política local llamado http_policy.pp.

De forma similar, podríamos crear una política para Samba con grep smbd_t /var/log/audit/audit.log | audit2allow -M smb_policy. Una vez generados, se cargan en la política activa con semodule -i http_policy.pp y semodule -i smb_policy.pp. Esto hace que las reglas generadas a partir de los registros se integren en SELinux y, en principio, dejen de aparecer denegaciones relacionadas con esos casos.

Aun así, conviene revisar a mano las reglas que produce audit2allow, porque tiende a ser generoso y puede conceder más permisos de los realmente necesarios. Una buena práctica es crear tipos más específicos y limitar los permisos a esos tipos dedicados, en lugar de abrir demasiado accesos a tipos generales. Cuando ciertas denegaciones no son críticas, puede ser mejor usar reglas dontaudit para que no generen ruido en los registros en lugar de permitirlas.

Desarrollo de módulos de política personalizados

En entornos complejos o aplicaciones desarrolladas internamente, es normal que no exista un módulo SELinux específico que las cubra. En esos casos, se recomienda desarrollar módulos propios que amplíen la política de referencia, en lugar de forzar todo dentro de políticas genéricas o booleans.

Para ello se instalan paquetes como selinux-policy-dev y selinux-policy-doc, que proporcionan tanto la documentación de las reglas estándar (por ejemplo en /usr/share/doc/selinux-policy-doc/html/) como archivos de ejemplo que sirven de plantilla. Es habitual copiar ficheros base como Makefile.example, example.fc, example.if y example.te a un directorio de trabajo para adaptarlos.

El archivo .te (type enforcement) es el corazón del módulo: en él se declaran los tipos, dominios y reglas allow/dontaudit. El archivo .fc (file contexts) define cómo se etiquetan los ficheros relacionados con el módulo, usando rutas y expresiones regulares. Por último, el archivo .if define interfaces públicas que otros módulos pueden invocar para interactuar con el nuestro, algo así como funciones reutilizables de alto nivel.

En un ejemplo típico, en el archivo .te se podría declarar un dominio myapp_t, el tipo ejecutable myapp_exec_t, un tipo para los logs myapp_log_t y otro para ficheros temporales myapp_tmp_t. Se usarían macros como domain_type(), domain_entry_file(), logging_log_file() o files_tmp_file() para estructurar bien la política, seguidas de reglas allow concretas que autoricen, por ejemplo, lectura y append sobre los ficheros de log y gestión de ficheros temporales.

En el archivo .if se definirían interfaces como myapp_domtrans (para controlar quién puede lanzar la aplicación y entrar en su dominio) o myapp_read_log (para permitir la lectura de sus registros a otros dominios). Cada interfaz debe declarar los tipos que necesita con gen_require y generar un bloque de reglas válido que, si se expandiera, pudiera integrarse sin problemas en un .te.

Una vez ajustados los tres archivos (interfaces, contexts y reglas), se renombran con el nombre real de la aplicación (por ejemplo, mi_programa.te, mi_programa.fc, mi_programa.if) y se compila el módulo con algo como make NAME=devel, lo que producirá un paquete de política mi_programa.pp. Este paquete se puede cargar de inmediato con semodule -i mi_programa.pp, y si hay varios módulos en el directorio, make generará todos los correspondientes .pp.

La parte más delicada del desarrollo de módulos es determinar el conjunto mínimo de reglas necesario para que la aplicación funcione sin romper el modelo de seguridad. Una técnica común es etiquetar correctamente todos los objetos que usa la aplicación, poner SELinux en modo permisivo y ejecutar la aplicación para que genere denegaciones en los registros, que luego se analizan con las herramientas de auditoría para ir afinando la política.

Encontrar el equilibrio entre funcionalidad y seguridad es un trabajo iterativo, pero bien llevado ofrece una protección muy granular que impide que una vulnerabilidad en una aplicación se convierta en un compromiso total del sistema.

SELinux pasa de ser «ese incordio que rompe servicios» a una herramienta potente y flexible que, bien configurada, aporta una capa de defensa de enorme valor frente a ataques y errores de configuración. Entender sus conceptos básicos —contextos, tipos, modos, booleans, etiquetado y módulos— es el primer paso para sacarle partido sin miedo.

cómo buscar configuraciones en Make Menuconfig
Artículo relacionado:
Cómo buscar configuraciones en make menuconfig y afinar tu kernel