AppArmor es el módulo de seguridad del kernel que Ubuntu y Debian activan por defecto para aplicar control de acceso obligatorio (MAC). A diferencia de SELinux, que etiqueta cada archivo, AppArmor funciona con perfiles basados en rutas: cada perfil indica qué archivos, capacidades y accesos de red puede usar un programa concreto, y todo lo demás se deniega. En este tutorial comprobarás el estado de AppArmor en Ubuntu 24.04, escribirás un perfil desde cero para confinar un script, lo probarás en modo complain y enforce, y aprenderás a ajustar los perfiles que instalan los paquetes sin modificar sus archivos.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
- Un usuario no root con privilegios
sudo. - Conocimientos básicos de la línea de comandos y de un editor como
nano.
Conceptos básicos
- Perfil: archivo de texto en
/etc/apparmor.d/que define los permisos de un programa. Por convención se nombra con la ruta del ejecutable cambiando/por., por ejemplousr.sbin.mysqld. - Modo enforce: el perfil se aplica y las acciones no permitidas se bloquean y se registran.
- Modo complain: el perfil no bloquea nada, solo registra lo que habría denegado. Sirve para desarrollar y ajustar perfiles.
- Abstracciones: fragmentos reutilizables en
/etc/apparmor.d/abstractions/(por ejemplobase,nameserviceossl_certs) que agrupan los accesos que casi todos los programas necesitan. - Overrides locales: archivos en
/etc/apparmor.d/local/que los perfiles del sistema incluyen, pensados para añadir permisos sin editar el perfil original.
Los permisos de archivo más usados son r (leer), w (escribir), a (añadir), k (bloquear), m (mapear como ejecutable) e ix (ejecutar otro programa heredando el mismo perfil).
Paso 1: Comprobar el estado de AppArmor
Instala las utilidades de administración. El paquete apparmor ya viene instalado, pero apparmor-utils añade aa-complain, aa-enforce, aa-genprof y aa-logprof:
sudo apt update
sudo apt install apparmor-utils
Comprueba que el servicio está activo y qué perfiles hay cargados:
systemctl is-active apparmor
sudo aa-status
apparmor module is loaded.
112 profiles are loaded.
33 profiles are in enforce mode.
/usr/bin/man
/usr/lib/snapd/snap-confine
rsyslogd
...
0 profiles are in complain mode.
3 processes have profiles defined.
3 processes are in enforce mode.
/usr/sbin/rsyslogd (812) rsyslogd
...
Las cifras varían según los paquetes instalados. La parte útil es la lista de procesos confinados y el modo de cada uno. Para ver con qué perfil corre cada proceso, usa ps con la columna de etiqueta:
ps -eo label,pid,comm | grep -v unconfined
Paso 2: Crear un programa de ejemplo
Para trabajar con un caso controlado, crea un pequeño script que genera un informe del sistema y lo guarda en /var/lib/reportgen. Acepta una ruta de salida opcional, lo que te permitirá comprobar después que el perfil impide escribir fuera de su directorio.
sudo nano /usr/local/bin/reportgen
#!/usr/bin/bash
set -euo pipefail
out="${1:-/var/lib/reportgen/report.txt}"
{
echo "Host: $(cat /etc/hostname)"
echo "Kernel: $(uname -r)"
echo "Fecha: $(date --iso-8601=seconds)"
} > "$out"
echo "Informe escrito en $out"
Hazlo ejecutable, crea el directorio de salida y pruébalo sin perfil:
sudo chmod 755 /usr/local/bin/reportgen
sudo mkdir -p /var/lib/reportgen
sudo /usr/local/bin/reportgen
sudo /usr/local/bin/reportgen /etc/reportgen-test.txt
Informe escrito en /var/lib/reportgen/report.txt
Informe escrito en /etc/reportgen-test.txt
Sin confinamiento, un script que se ejecuta como root puede escribir en cualquier parte. Borra el archivo de prueba:
sudo rm /etc/reportgen-test.txt
Paso 3: Escribir el perfil
Crea el perfil en /etc/apparmor.d/ siguiendo la convención de nombres:
sudo nano /etc/apparmor.d/usr.local.bin.reportgen
abi <abi/4.0>,
include <tunables/global>
profile reportgen /usr/local/bin/reportgen {
include <abstractions/base>
include <abstractions/bash>
include <abstractions/consoles>
# El propio script y los binarios que ejecuta
/usr/local/bin/reportgen r,
/usr/bin/bash ix,
/usr/bin/{cat,date,uname} ix,
# Datos que lee y escribe
/etc/hostname r,
/var/lib/reportgen/ r,
/var/lib/reportgen/** rw,
include if exists <local/usr.local.bin.reportgen>
}
Qué hace cada parte:
abi <abi/4.0>fija la versión de las reglas; Ubuntu 24.04 incluye AppArmor 4.profile reportgen /usr/local/bin/reportgenda nombre al perfil y lo asocia a esa ruta.- Las abstracciones
base,bashyconsolescubren bibliotecas, locales, archivos de inicio de Bash y la terminal. ixpermite ejecutarbash,cat,dateyunamedentro del mismo perfil, así heredan las mismas restricciones.- Solo se permite leer
/etc/hostnamey escribir dentro de/var/lib/reportgen/. - La última línea incluye un override local si existe, igual que hacen los perfiles del sistema.
Carga el perfil en el kernel. apparmor_parser -r lo compila y lo reemplaza si ya estaba cargado; si hay un error de sintaxis, te dirá la línea:
sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.reportgen
sudo aa-status | grep reportgen
reportgen
Los perfiles nuevos se cargan en modo enforce.
Paso 4: Probar el perfil en modo enforce
Ejecuta el script con la ruta permitida:
sudo /usr/local/bin/reportgen
cat /var/lib/reportgen/report.txt
Informe escrito en /var/lib/reportgen/report.txt
Host: servidor01
Kernel: 6.8.0-45-generic
Fecha: 2026-09-25T10:15:02+00:00
Ahora intenta escribir fuera de su directorio, aunque lo ejecutes como root:
sudo /usr/local/bin/reportgen /etc/reportgen-test.txt
/usr/local/bin/reportgen: line 10: /etc/reportgen-test.txt: Permission denied
La denegación queda registrada en el log del kernel:
sudo journalctl -k --since "5 minutes ago" | grep 'apparmor="DENIED"'
audit: type=1400 audit(1727259302.512:210): apparmor="DENIED" operation="mknod" class="file" profile="reportgen" name="/etc/reportgen-test.txt" pid=4312 comm="reportgen" requested_mask="c" denied_mask="c" fsuid=0 ouid=0
Los campos clave son profile (qué perfil denegó), name (el recurso) y denied_mask (el permiso que faltaba: c crear, r leer, w escribir, x ejecutar).
Paso 5: Ajustar un perfil con el modo complain
Cuando confinas un programa real no sueles conocer de antemano todo lo que necesita. El flujo recomendado es poner el perfil en complain, usar el programa con normalidad y dejar que aa-logprof proponga las reglas que faltan.
Supón que el script tiene que leer también /etc/os-release. Añade esta línea dentro del bloque { } del script, justo después del echo del kernel:
echo "Sistema: $(grep PRETTY_NAME /etc/os-release)"
Pon el perfil en complain y ejecuta el script:
sudo aa-complain /usr/local/bin/reportgen
sudo /usr/local/bin/reportgen
En complain el script funciona, pero cada acceso no previsto se registra con apparmor="ALLOWED". Revisa esos eventos con aa-logprof, que lee los logs del sistema y te pregunta regla por regla:
sudo aa-logprof
Para cada evento puedes elegir (A)llow para aceptar la regla propuesta, (D)eny para denegarla explícitamente o (G)lob para generalizar la ruta. Al final pulsa S para guardar los cambios en el perfil. Comprueba el resultado y vuelve a enforce:
sudo cat /etc/apparmor.d/usr.local.bin.reportgen
sudo aa-enforce /usr/local/bin/reportgen
Consejopara un programa nuevo sin ningún perfil,
sudo aa-genprof /ruta/al/programacrea un perfil básico, lo pone en complain y te guía para ejecutar el programa en otra terminal y responder a las preguntas. Es el mismo flujo queaa-logprof, pero partiendo de cero.
Paso 6: Ajustar perfiles del sistema con overrides locales
Los paquetes instalan sus propios perfiles, y si los editas directamente, la próxima actualización puede sobrescribir tus cambios. Por eso casi todos incluyen una línea como include if exists <local/usr.sbin.mysqld> para que añadas permisos en /etc/apparmor.d/local/.
Un ejemplo típico: mueves el directorio de datos de MySQL a /srv/mysql y el servicio deja de arrancar porque el perfil usr.sbin.mysqld no permite esa ruta. Con MySQL instalado desde los repositorios de Ubuntu, edita el override local:
sudo nano /etc/apparmor.d/local/usr.sbin.mysqld
/srv/mysql/ r,
/srv/mysql/** rwk,
Recarga el perfil principal, que incluye el override:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld
sudo systemctl restart mysql
El mismo patrón sirve para cualquier perfil del sistema: busca la línea include if exists <local/...> en el perfil y crea ese archivo.
Paso 7: Desactivar o eliminar un perfil
Si un perfil da problemas y necesitas desactivarlo mientras lo investigas, prefiere el modo complain, que sigue registrando. Si realmente necesitas desactivarlo, usa aa-disable, que descarga el perfil y crea un enlace en /etc/apparmor.d/disable/ para que no se cargue en el siguiente arranque:
sudo aa-disable /usr/local/bin/reportgen
Para reactivarlo, elimina el enlace y vuelve a cargarlo:
sudo rm /etc/apparmor.d/disable/usr.local.bin.reportgen
sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.reportgen
Para eliminar el perfil de ejemplo por completo:
sudo apparmor_parser -R /etc/apparmor.d/usr.local.bin.reportgen
sudo rm /etc/apparmor.d/usr.local.bin.reportgen
Solución de problemas
apparmor_parsermuestra un error de sintaxis: revisa la línea indicada. Los errores más comunes son olvidar la coma al final de una regla o cerrar mal las llaves.- El programa falla sin mensaje claro: busca denegaciones con
sudo journalctl -k | grep 'apparmor="DENIED"'filtrando por el nombre del perfil. Si no aparece nada, AppArmor no es la causa. aa-logprofno encuentra eventos: lee/var/log/syslogo, si tienesauditdinstalado,/var/log/audit/audit.log. Si usas otro log, indícalo consudo aa-logprof -f /ruta/al/log.- Un cambio en el perfil no tiene efecto: los cambios en disco no se aplican hasta recargar el perfil con
sudo apparmor_parser -ro reiniciar el servicioapparmor. Los procesos que ya estaban en ejecución deben reiniciarse.
Conclusión
Has comprobado el estado de AppArmor, escrito y cargado un perfil propio, verificado que bloquea escrituras no permitidas incluso para root, ajustado el perfil con aa-logprof en modo complain y añadido permisos a perfiles del sistema mediante overrides locales. Como siguientes pasos, puedes aplicar el mismo flujo con aa-genprof a un servicio propio que ejecutes con systemd, revisar los perfiles adicionales del paquete apparmor-profiles y combinar AppArmor con un cortafuegos UFW bien configurado.
