Introducción: Por qué el control de acceso obligatorio ya no es opcional
Si administras servidores Linux en producción y todavía no tienes SELinux o AppArmor en modo enforcing, voy a ser directo: estás dejando una de las capas de defensa más potentes completamente desactivada. Y en 2026, con ciclos de explotación que se miden en horas y reconocimiento asistido por IA, eso es un riesgo que simplemente no te puedes permitir.
El modelo de permisos tradicional de Linux — el famoso propietario-grupo-otros (DAC, Control de Acceso Discrecional) — tiene una limitación fundamental: si un proceso se ejecuta como root, tiene acceso a prácticamente todo. Si un atacante compromete tu servidor web Apache o tu instancia de PostgreSQL, y ese servicio corre con privilegios elevados, el DAC solo no va a contener el daño.
Aquí es donde entra el Control de Acceso Obligatorio (MAC).
SELinux y AppArmor implementan políticas que el propio kernel aplica de forma estricta. Da igual que un proceso sea root — si la política MAC dice que nginx no puede leer /etc/shadow, no lo va a hacer. Punto. Es la diferencia entre «confiar en que los procesos se comporten bien» y «asegurarse de que no puedan hacer nada fuera de lo estrictamente necesario».
En esta guía vamos a ir bastante más allá de la teoría. Vas a aprender a configurar, administrar y crear políticas personalizadas tanto en SELinux como en AppArmor, con ejemplos reales aplicados a servidores web, bases de datos y aplicaciones custom. Todo actualizado a 2026, incluyendo los cambios más recientes del kernel y las mejores prácticas para producción.
DAC vs MAC: Entendiendo la diferencia fundamental
Antes de meternos en la configuración, necesitas entender bien por qué MAC existe y qué problema resuelve. No es redundante con los permisos Unix — es una capa completamente diferente.
Control de Acceso Discrecional (DAC)
Es el modelo clásico de permisos Unix. El propietario de un archivo decide quién puede leer, escribir o ejecutar. El problema es que es «discrecional»: el propietario (o root) puede cambiar los permisos cuando quiera. Si un atacante obtiene acceso root, el DAC deja de ser una barrera real.
Control de Acceso Obligatorio (MAC)
MAC opera a nivel del kernel. Las políticas las define el administrador de seguridad, y ni siquiera root puede saltárselas sin autorización explícita de la política. Es como pasar de «los empleados deciden quién entra en su oficina» a «el sistema de seguridad del edificio controla todas las puertas y no hace excepciones».
Ambos modelos coexisten en Linux. El kernel primero verifica los permisos DAC, y si el acceso está permitido, entonces consulta la política MAC. Si cualquiera de los dos dice «no», el acceso se deniega. Así de simple.
SELinux: Control granular basado en etiquetas
SELinux (Security-Enhanced Linux) fue desarrollado originalmente por la NSA y es el sistema MAC predeterminado en RHEL, Rocky Linux, AlmaLinux, CentOS Stream y Fedora. Un dato interesante: en febrero de 2025, openSUSE Tumbleweed también adoptó SELinux por defecto para nuevas instalaciones, lo que marca una tendencia clara en la industria.
Conceptos fundamentales de SELinux
SELinux asigna un contexto de seguridad a cada objeto del sistema: archivos, procesos, puertos de red, sockets. Un contexto tiene cuatro campos:
usuario:rol:tipo:nivel
# Ejemplo real:
system_u:system_r:httpd_t:s0
El campo más importante para el trabajo diario es el tipo. La mayoría de las decisiones de política se basan en las reglas de Type Enforcement (TE), que definen qué tipos de proceso pueden acceder a qué tipos de recurso.
Por ejemplo, el proceso de Apache tiene el tipo httpd_t, y los archivos web en /var/www/html/ tienen el tipo httpd_sys_content_t. La política permite que httpd_t lea httpd_sys_content_t, pero le prohíbe acceder a shadow_t (el tipo de /etc/shadow). Si un atacante compromete Apache, queda atrapado dentro de lo que la política permite a httpd_t.
Modos de operación
SELinux opera en tres modos. Verificarlos y cambiarlos es lo primero que necesitas saber:
# Ver el modo actual
getenforce
# Resultado: Enforcing, Permissive o Disabled
# Ver estado detallado
sestatus
# Cambiar temporalmente (no sobrevive a reinicio)
sudo setenforce 0 # Cambiar a Permissive
sudo setenforce 1 # Cambiar a Enforcing
Para un cambio permanente, edita /etc/selinux/config:
# /etc/selinux/config
SELINUX=enforcing
SELINUXTYPE=targeted
Regla de oro: nunca desactives SELinux en producción. Si algo no funciona, usa modo permissive para diagnosticar, pero el objetivo siempre es volver a enforcing. He visto demasiados servidores con SELINUX=disabled porque «algo no funcionaba» hace tres años y nadie se molestó en investigar.
Trabajar con contextos de seguridad
Los contextos son la base de todo en SELinux. Necesitas saber consultarlos y modificarlos:
# Ver contexto de archivos
ls -Z /var/www/html/
# -rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
# Ver contexto de procesos
ps auxZ | grep httpd
# system_u:system_r:httpd_t:s0 root 1234 ... /usr/sbin/httpd
# Ver contexto de puertos
semanage port -l | grep http
# http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
# Cambiar el contexto de un archivo
sudo chcon -t httpd_sys_content_t /var/www/miapp/config.php
# Restaurar contextos por defecto según la política
sudo restorecon -Rv /var/www/html/
Booleanos: Ajustes rápidos sin tocar la política
Los booleanos de SELinux son interruptores on/off que modifican el comportamiento de la política sin necesidad de crear módulos personalizados. Son tu primera herramienta cuando algo no funciona como esperas:
# Listar todos los booleanos (son cientos)
getsebool -a
# Buscar booleanos relacionados con httpd
getsebool -a | grep httpd
# Permitir que Apache se conecte a la red (para proxy reverso, por ejemplo)
sudo setsebool -P httpd_can_network_connect on
# Permitir que Apache acceda a directorios home
sudo setsebool -P httpd_enable_homedirs on
# El flag -P hace el cambio persistente (sobrevive a reinicios)
Diagnóstico de denegaciones con audit2why y ausearch
Cuando SELinux bloquea algo, registra un mensaje AVC (Access Vector Cache) en /var/log/audit/audit.log. Aquí es donde la mayoría de administradores se frustran — pero honestamente, con las herramientas correctas, el diagnóstico es bastante directo:
# Ver denegaciones recientes
sudo ausearch -m avc -ts today
# Obtener explicación legible de las denegaciones
sudo ausearch -m avc -ts today | audit2why
# Ejemplo de salida de audit2why:
# type=AVC msg=audit(1710000000.123:456): avc: denied { name_connect }
# for pid=1234 comm="httpd" dest=5432
# scontext=system_u:system_r:httpd_t:s0
# tcontext=system_u:object_r:postgresql_port_t:s0
#
# Was caused by:
# One of the following booleans was set incorrectly.
# Allow httpd to can network connect db:
# setsebool -P httpd_can_network_connect_db on
En este ejemplo, Apache intenta conectarse al puerto 5432 (PostgreSQL) y SELinux lo bloquea. audit2why te dice exactamente qué booleano activar. Así de fácil.
Crear módulos de política personalizados
Cuando ni los booleanos ni los contextos resuelven tu problema, toca crear un módulo de política personalizado. Esto es más común de lo que parece — cualquier aplicación que no sea un servicio estándar probablemente necesitará uno:
# Paso 1: Identificar las denegaciones para tu aplicación
sudo ausearch -m avc -ts today -c miapp
# Paso 2: Generar el módulo automáticamente con audit2allow
sudo ausearch -m avc -ts today -c miapp | audit2allow -M miapp_policy
# Esto genera dos archivos:
# miapp_policy.te (código fuente de la política)
# miapp_policy.pp (módulo compilado)
# Paso 3: Revisar el .te ANTES de instalar (esto es crítico)
cat miapp_policy.te
# Paso 4: Instalar el módulo
sudo semodule -i miapp_policy.pp
# Paso 5: Verificar que el módulo está cargado
sudo semodule -l | grep miapp
Advertencia importante: nunca instales un módulo generado por audit2allow sin revisar el archivo .te primero. La herramienta genera permisos para todo lo que fue denegado, y eso puede incluir accesos que no deberías permitir. Revisa cada regla allow y elimina las que no sean estrictamente necesarias.
Ejemplo práctico: Política personalizada para Nginx con puerto no estándar
Supongamos que quieres ejecutar Nginx en el puerto 8090 y servir contenido desde /opt/webapp/public. Este es un escenario que me encuentro constantemente:
# Paso 1: Añadir el puerto al tipo http_port_t
sudo semanage port -a -t http_port_t -p tcp 8090
# Paso 2: Etiquetar el directorio de contenido
sudo semanage fcontext -a -t httpd_sys_content_t "/opt/webapp/public(/.*)?"
sudo restorecon -Rv /opt/webapp/public
# Paso 3: Si Nginx necesita escribir logs en ubicación personalizada
sudo semanage fcontext -a -t httpd_log_t "/opt/webapp/logs(/.*)?"
sudo restorecon -Rv /opt/webapp/logs
# Paso 4: Si Nginx se conecta a un backend (proxy reverso)
sudo setsebool -P httpd_can_network_connect on
# Paso 5: Verificar que todo funciona
sudo systemctl restart nginx
curl http://localhost:8090
AppArmor: Protección basada en perfiles y rutas
AppArmor es el sistema MAC predeterminado en Ubuntu, Debian y SUSE Linux Enterprise. Su filosofía es diferente a SELinux: en lugar de etiquetar objetos, define perfiles por aplicación que especifican exactamente a qué rutas del sistema de archivos y qué capacidades puede acceder cada programa.
Conceptos fundamentales de AppArmor
En AppArmor, cada aplicación confinada tiene un perfil que lista sus permisos. Si una aplicación intenta hacer algo que su perfil no permite, AppArmor lo bloquea. Es un modelo bastante más intuitivo que SELinux porque piensas en términos de «qué puede hacer esta aplicación» en lugar de «qué etiquetas tienen los objetos».
Los perfiles se almacenan como archivos de texto en /etc/apparmor.d/ y usan una sintaxis relativamente legible (que se agradece, la verdad):
# Estructura básica de un perfil AppArmor
/usr/sbin/nginx {
# Incluir abstracciones comunes
#include <abstractions/base>
#include <abstractions/nameservice>
# Permisos de lectura para contenido web
/var/www/html/** r,
# Permisos de escritura para logs
/var/log/nginx/** w,
# Acceso al socket
network inet tcp,
# Capacidades necesarias
capability net_bind_service,
capability setuid,
capability setgid,
}
Modos de operación
AppArmor tiene dos modos principales para cada perfil:
- Enforce: la política se aplica activamente. Las violaciones se bloquean y se registran.
- Complain: las violaciones solo se registran, sin bloquear nada. Equivalente al modo permissive de SELinux — ideal para desarrollar y probar perfiles.
# Instalar herramientas de AppArmor (Debian/Ubuntu)
sudo apt install apparmor apparmor-profiles apparmor-utils
# Ver estado general de AppArmor
sudo aa-status
# Ver perfiles en modo enforce
sudo aa-status | grep enforce
# Poner un perfil en modo complain
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
# Poner un perfil en modo enforce
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
# Desactivar un perfil específico (sin desactivar AppArmor)
sudo aa-disable /etc/apparmor.d/usr.sbin.nginx
Crear un perfil personalizado desde cero
AppArmor incluye herramientas que simplifican enormemente la creación de perfiles. El flujo de trabajo estándar es bastante amigable:
# Paso 1: Generar un perfil esqueleto
sudo aa-genprof /opt/miapp/bin/miapp
# aa-genprof te pedirá que ejercites la aplicación.
# Ejecuta tu aplicación normalmente en otra terminal:
# /opt/miapp/bin/miapp --start
# Paso 2: aa-genprof analiza los logs y te pregunta
# qué permisos añadir. Responde según lo que tu app necesita.
# Paso 3: Una vez terminado, el perfil se guarda automáticamente en
# /etc/apparmor.d/opt.miapp.bin.miapp
Si prefieres un enfoque más manual (o necesitas refinar algo después), puedes usar aa-logprof para ajustar un perfil existente basándote en las violaciones registradas:
# Poner el perfil en modo complain
sudo aa-complain /etc/apparmor.d/opt.miapp.bin.miapp
# Ejercitar la aplicación normalmente durante un período
# Analizar los logs y actualizar el perfil
sudo aa-logprof
# Cuando estés satisfecho, pasar a enforce
sudo aa-enforce /etc/apparmor.d/opt.miapp.bin.miapp
Ejemplo práctico: Perfil personalizado para PostgreSQL
Vamos a crear un perfil AppArmor robusto para PostgreSQL que restrinja su acceso al mínimo necesario. Este tipo de perfil es algo que deberías tener en cualquier servidor de base de datos:
# /etc/apparmor.d/usr.lib.postgresql.16.bin.postgres
#include <tunables/global>
/usr/lib/postgresql/16/bin/postgres {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/ssl_certs>
# Binario principal
/usr/lib/postgresql/16/bin/postgres mr,
/usr/lib/postgresql/16/bin/* rix,
/usr/lib/postgresql/16/lib/** mr,
# Directorio de datos
/var/lib/postgresql/16/main/** rwk,
/var/lib/postgresql/16/main/ r,
# Archivos de configuración
/etc/postgresql/16/main/** r,
# Logs
/var/log/postgresql/** rw,
# Socket Unix
/var/run/postgresql/ r,
/var/run/postgresql/** rw,
# Archivos temporales
/tmp/ r,
/tmp/pg_* rw,
# Red (solo escuchar en puerto local)
network inet stream,
network inet6 stream,
network unix stream,
# Capacidades necesarias
capability setuid,
capability setgid,
capability fowner,
capability chown,
capability dac_override,
# Denegar explícitamente acceso a rutas sensibles
deny /etc/shadow r,
deny /etc/gshadow r,
deny /root/** rw,
deny /home/** rw,
}
# Cargar el perfil
sudo apparmor_parser -r /etc/apparmor.d/usr.lib.postgresql.16.bin.postgres
# Verificar que está activo
sudo aa-status | grep postgres
Sintaxis de permisos en AppArmor
Para escribir perfiles que funcionen bien, necesitas conocer los permisos disponibles:
r— lecturaw— escrituraa— append (solo añadir, no sobrescribir)k— bloqueo de archivos (file locking)l— enlace (link)m— mmap ejecutableix— ejecutar heredando el perfil actualpx— ejecutar con transición a otro perfilux— ejecutar sin confinamiento (usar con mucha precaución)cx— ejecutar con transición a un perfil hijo
SELinux vs AppArmor: Comparación directa para 2026
Esta es la pregunta que todo el mundo hace, así que vamos al grano:
| Criterio | SELinux | AppArmor |
|---|---|---|
| Modelo de control | Etiquetas (labels) asignadas a cada objeto | Rutas de archivos (paths) en perfiles por app |
| Distribuciones | RHEL, Rocky, Alma, Fedora, openSUSE Tumbleweed | Ubuntu, Debian, SUSE Enterprise |
| Curva de aprendizaje | Pronunciada — requiere entender contextos, tipos, roles | Moderada — los perfiles son legibles y la sintaxis es intuitiva |
| Granularidad | Extremadamente alta — MLS, MCS, RBAC | Buena — suficiente para la mayoría de escenarios |
| Rendimiento | Optimizado para entornos empresariales | Menor overhead, procesamiento de reglas más simple |
| Herramientas de diagnóstico | audit2why, audit2allow, sesearch, seinfo | aa-status, aa-logprof, aa-genprof, aa-complain |
| Contenerización | Excelente aislamiento con etiquetas MCS | Perfiles por contenedor, integración con Docker/Snap |
| Creación de políticas | Compleja — archivos .te, .if, .fc, compilación | Sencilla — archivos de texto con generación asistida |
¿Cuál elegir?
La respuesta honesta: usa el que venga con tu distribución. Si estás en RHEL/Rocky/Alma/Fedora, usa SELinux. Si estás en Ubuntu/Debian, usa AppArmor. Cambiar de uno a otro es posible pero rara vez vale la pena — ambos proporcionan una defensa MAC sólida cuando están bien configurados.
Dicho esto, hay excepciones legítimas:
- Entornos de alta seguridad (gobierno, finanzas, cumplimiento PCI-DSS/HIPAA): SELinux ofrece el control MLS/MCS que AppArmor no tiene.
- Equipos pequeños sin especialistas de seguridad: AppArmor es más fácil de mantener y genera menos fricción operativa en el día a día.
- Entornos mixtos con contenedores: ambos funcionan bien, pero SELinux con etiquetas MCS ofrece un aislamiento entre contenedores más robusto.
Novedades de 2026: Lo que ha cambiado
El ecosistema MAC en Linux está evolucionando bastante rápido. Estos son los cambios más relevantes que deberías tener en el radar:
openSUSE adopta SELinux por defecto
Desde febrero de 2025, openSUSE Tumbleweed usa SELinux en lugar de AppArmor para nuevas instalaciones. openSUSE Leap 16 sigue el mismo camino. Es un cambio significativo que muestra la creciente adopción de SELinux más allá del ecosistema Red Hat.
AppArmor se prepara para una renovación mayor en Linux 7.0
Los desarrolladores del kernel están preparando una renovación sustancial de AppArmor para Linux 7.0. Los cambios son bastante prometedores:
- Arquitectura de permisos flexible: el modelo actual se ha descrito como rígido y difícil de extender. La nueva arquitectura permitirá políticas más granulares para subsistemas modernos del kernel como user namespaces, io_uring y eBPF.
- Compatibilidad completa con LSM stacking: la capacidad de ejecutar múltiples módulos de seguridad simultáneamente (por ejemplo, AppArmor junto con otro LSM), algo especialmente relevante para contenedores.
- Notificaciones mejoradas a espacio de usuario: un sistema de notificaciones más robusto que permitirá diálogos de permisos similares a los de macOS o Android en escritorios Linux. Esto podría cambiar bastante la experiencia de usuario.
eBPF como complemento de MAC
En 2026, las herramientas de seguridad basadas en eBPF como Cilium Tetragon y BPF LSM están ganando mucha tracción. No reemplazan a SELinux/AppArmor, pero los complementan con capacidad de aplicar políticas dinámicas sin recompilar el kernel. Con programas eBPF firmados y verificados, puedes crear reglas de seguridad en tiempo de ejecución que trabajen junto con tu política MAC existente.
Fedora alinea su política SELinux con el kernel actual
Fedora ha actualizado su selinux-policy para reflejar las nuevas características del kernel, incluyendo mayor granularidad en los permisos y soporte para subsistemas más recientes. Si usas Fedora o derivados, asegúrate de tener la política al día.
Integración con contenedores: Docker y Podman
La seguridad MAC no termina en el host — es fundamental para aislar contenedores. Y honestamente, aquí es donde SELinux y AppArmor demuestran su valor real en entornos modernos:
SELinux con contenedores
Cuando usas Podman o Docker en un sistema con SELinux, cada contenedor recibe automáticamente una etiqueta MCS (Multi-Category Security) única. Esto significa que un contenedor comprometido no puede acceder a los archivos de otro contenedor, incluso si ambos corren como root:
# Verificar las etiquetas SELinux de contenedores Podman
sudo podman ps --format "{{.Names}} {{.Labels}}"
# Ejecutar un contenedor con etiqueta SELinux personalizada
sudo podman run --security-opt label=type:container_t \
--security-opt label=level:s0:c100,c200 \
-d nginx
# Montar volúmenes con la etiqueta correcta
# :z — contexto compartido (varios contenedores pueden acceder)
# :Z — contexto privado (solo este contenedor)
sudo podman run -v /datos/web:/usr/share/nginx/html:Z -d nginx
AppArmor con contenedores
Docker en Ubuntu aplica automáticamente el perfil docker-default de AppArmor a cada contenedor. Pero puedes (y deberías) crear perfiles personalizados para contenedores específicos:
# Perfil AppArmor personalizado para un contenedor de aplicación
# /etc/apparmor.d/docker-webapp
#include <tunables/global>
profile docker-webapp flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
# Acceso a la red
network inet tcp,
network inet udp,
# Solo lectura del sistema de archivos del contenedor
/ r,
/** r,
# Escritura solo en directorios específicos
/app/data/** rw,
/tmp/** rw,
/var/log/app/** rw,
# Denegar acceso a información sensible del host
deny /proc/*/mem r,
deny /sys/firmware/** r,
# Capacidades mínimas
capability net_bind_service,
capability setuid,
capability setgid,
}
# Cargar el perfil
sudo apparmor_parser -r /etc/apparmor.d/docker-webapp
# Ejecutar el contenedor con el perfil personalizado
docker run --security-opt apparmor=docker-webapp -d miapp:latest
Automatización con Ansible: MAC a escala
Configurar MAC manualmente en uno o dos servidores es manejable. Pero cuando gestionas decenas o cientos de nodos, necesitas automatización. Ansible encaja perfectamente aquí:
Playbook para SELinux
# selinux-hardening.yml
---
- name: Configurar SELinux en modo enforcing
hosts: servidores_produccion
become: yes
tasks:
- name: Asegurar que SELinux está en modo enforcing
ansible.posix.selinux:
policy: targeted
state: enforcing
- name: Configurar booleanos de SELinux para servidores web
ansible.posix.seboolean:
name: "{{ item.name }}"
state: "{{ item.state }}"
persistent: yes
loop:
- { name: httpd_can_network_connect, state: yes }
- { name: httpd_can_network_connect_db, state: yes }
- { name: httpd_use_nfs, state: no }
- { name: httpd_enable_cgi, state: no }
- name: Configurar contextos personalizados
community.general.sefcontext:
target: "/opt/webapp/public(/.*)?"
setype: httpd_sys_content_t
state: present
notify: restorecon webapp
- name: Añadir puerto personalizado para HTTP
community.general.seport:
ports: 8090
proto: tcp
setype: http_port_t
state: present
handlers:
- name: restorecon webapp
command: restorecon -Rv /opt/webapp/public
Playbook para AppArmor
# apparmor-hardening.yml
---
- name: Configurar AppArmor en servidores Ubuntu
hosts: servidores_ubuntu
become: yes
tasks:
- name: Asegurar que AppArmor está instalado y activo
apt:
name:
- apparmor
- apparmor-profiles
- apparmor-profiles-extra
- apparmor-utils
state: present
- name: Desplegar perfil personalizado para la aplicación
copy:
src: files/apparmor/opt.miapp.bin.miapp
dest: /etc/apparmor.d/opt.miapp.bin.miapp
owner: root
group: root
mode: "0644"
notify: recargar apparmor
- name: Verificar que perfiles críticos están en modo enforce
command: aa-enforce /etc/apparmor.d/{{ item }}
loop:
- usr.sbin.nginx
- usr.sbin.mysqld
- opt.miapp.bin.miapp
handlers:
- name: recargar apparmor
command: apparmor_parser -r /etc/apparmor.d/opt.miapp.bin.miapp
Resolución de problemas comunes
Vamos con los escenarios que más vas a encontrarte en el día a día. Los he ordenado por frecuencia:
SELinux: «Mi aplicación no arranca»
# 1. Verificar si SELinux es el problema
sudo setenforce 0
# Intentar arrancar la aplicación
# Si funciona -> es problema de SELinux
sudo setenforce 1
# 2. Buscar las denegaciones específicas
sudo ausearch -m avc -ts recent -c nombre_app
# 3. Obtener la solución sugerida
sudo ausearch -m avc -ts recent -c nombre_app | audit2why
# 4. Si es un problema de contexto de archivos
sudo restorecon -Rv /ruta/de/la/aplicacion
# 5. Si necesitas un módulo personalizado
sudo ausearch -m avc -ts recent -c nombre_app | audit2allow -M fix_miapp
# REVISAR fix_miapp.te antes de instalar
sudo semodule -i fix_miapp.pp
AppArmor: «Permiso denegado pero los permisos Unix son correctos»
Este es un clásico. Los permisos del sistema de archivos se ven bien, pero la aplicación sigue sin poder acceder a lo que necesita:
# 1. Verificar si AppArmor está bloqueando
sudo dmesg | grep "apparmor.*DENIED"
# También puedes revisar el journal
sudo journalctl -k | grep apparmor
# 2. Poner el perfil en modo complain temporalmente
sudo aa-complain /etc/apparmor.d/perfil_problematico
# 3. Ejecutar la aplicación y analizar los logs
sudo aa-logprof
# 4. Añadir las reglas necesarias y volver a enforce
sudo aa-enforce /etc/apparmor.d/perfil_problematico
Problema con volúmenes montados y SELinux
Otro que aparece todo el tiempo, especialmente con NFS y montajes externos:
# Error típico: nginx no puede leer archivos de un NFS o un montaje externo
# Solución 1: Re-etiquetar los archivos
sudo chcon -R -t httpd_sys_content_t /mnt/datos/web
# Solución 2: Si es NFS, activar el booleano correspondiente
sudo setsebool -P httpd_use_nfs on
# Solución 3: Para montajes genéricos de almacenamiento
sudo setsebool -P httpd_use_fusefs on
Checklist de implementación MAC para producción
Antes de considerar tu implementación MAC completa, revisa estos puntos. Los tengo como referencia rápida cada vez que configuro un servidor nuevo:
- El módulo MAC está en modo enforcing — no permissive, no disabled.
- Todos los servicios expuestos a red tienen política/perfil activo — nginx, Apache, PostgreSQL, MySQL, aplicaciones custom.
- Los contextos/perfiles están probados — ejecutaste las aplicaciones en modo permissive/complain primero.
- Las denegaciones esperadas se manejan — no hay avalanchas de mensajes AVC/DENIED en los logs.
- La automatización está en su lugar — Ansible u otra herramienta gestiona la configuración MAC de forma consistente.
- El equipo sabe diagnosticar problemas — conocen audit2why/aa-logprof y saben cuándo usarlos.
- Los contenedores tienen políticas específicas — no dependen solo del perfil/política por defecto.
- Los cambios se documentan — cada módulo personalizado o booleano tiene una justificación registrada.
Preguntas frecuentes
¿Puedo usar SELinux y AppArmor al mismo tiempo?
Históricamente no era posible porque ambos son módulos LSM (Linux Security Modules) y el kernel solo permitía uno activo. Sin embargo, las versiones recientes del kernel soportan LSM stacking, que permite ejecutar múltiples módulos simultáneamente. En la práctica, esto es más relevante para entornos de contenedores donde el host usa un LSM y los contenedores podrían necesitar otro. Para un servidor estándar, elige uno y quédate con él.
¿Desactivar SELinux o AppArmor mejora el rendimiento?
No de forma significativa. Estudios recientes muestran una diferencia del 0,2% al 0,8%, que está dentro del margen de ruido estadístico. Las pruebas con sockperf y dbench confirman que el overhead es insignificante en cargas de trabajo reales. El argumento del rendimiento no justifica desactivar MAC en ningún escenario.
¿Qué pasa si instalo software nuevo y SELinux lo bloquea?
Es el comportamiento esperado y deseable. SELinux opera con una filosofía de «denegación por defecto»: si no hay una regla que permita una acción, se bloquea. El flujo correcto es: instalar el software, revisar los logs con ausearch y audit2why, configurar los booleanos o contextos necesarios, y solo si eso no basta, crear un módulo de política personalizado mínimo. Nada de desactivar SELinux «porque no funciona».
¿AppArmor protege contra ataques de escalada de privilegios?
Sí, y de forma bastante efectiva. Un perfil AppArmor bien configurado limita lo que un proceso puede hacer incluso si un atacante logra ejecutar código arbitrario dentro de ese proceso. Si un servidor web es comprometido pero su perfil deniega acceso a /etc/shadow y a la ejecución de shells, el atacante queda contenido. No es infalible — un exploit del kernel podría evadir AppArmor — pero eleva enormemente la barrera para el atacante.
¿Cómo se integra el MAC con los CIS Benchmarks de 2026?
Los CIS Benchmarks para Linux (actualizados en 2026) requieren explícitamente que un sistema MAC esté activo en modo enforcing. El Nivel 1 exige que SELinux o AppArmor esté habilitado y configurado. El Nivel 2 va más allá, requiriendo políticas ajustadas para cada servicio y la eliminación de perfiles en modo unconfined. Si buscas cumplimiento CIS, MAC no es opcional — es un requisito de línea base.