Los permisos en Linux responden a la pregunta «quién puede leer este archivo». AppArmor responde a otra: «qué se le permite hacer a este programa». La diferencia se ve durante una intrusión. Un web shell se ejecuta con el usuario del servidor web y hereda todos sus permisos, es decir, la lectura de medio sistema. Un perfil de AppArmor limita el proceso a la lista de lo que necesita para trabajar, y un intento de leer /etc/shadow o de lanzar /bin/bash termina en una negativa, con independencia de los permisos del usuario.
Qué está ya activo
sudo aa-status
La salida responde a tres preguntas: cuántos perfiles hay cargados, cuántos de ellos están en modo enforce y complain, y qué procesos funcionan sin perfil alguno. En un Ubuntu típico habrá varias decenas de perfiles, pero casi todos para utilidades como man y tcpdump. Los servicios clave —nginx, Apache, PHP-FPM— suelen faltar en la lista de procesos confinados.
Tres modos que hay que distinguir:
- enforce: las reglas se aplican, todo lo sobrante queda prohibido;
- complain: las infracciones solo se registran, no se bloquea nada. Es el modo de ajuste;
- unconfined: no hay perfil, el programa funciona sin restricciones.
La parte más útil de la salida de aa-status es la última: los procesos que escuchan en la red y no están limitados por nada. Esa es la lista por la que empezar.
Las herramientas
sudo apt install apparmor-utils
Sin ese paquete, los comandos aa-complain, aa-enforce y aa-logprof no existen en el sistema, aunque AppArmor sí funcione.
Cómo activar un perfil sin detener el servicio
El orden es fundamental. Un perfil puesto de golpe en enforce le prohibirá al servicio, con alta probabilidad, algo necesario, y dejará de funcionar; normalmente no de inmediato, sino en una operación poco frecuente como una subida de archivo o el envío de correo.
La secuencia correcta:
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
Una semana de funcionamiento en ese modo, cubriendo todos los escenarios excepcionales: una copia de seguridad, una actualización, la subida de archivos grandes. Después, el repaso de lo acumulado:
sudo aa-logprof
El comando recorre las infracciones registradas y pregunta por cada una si debe permitirse. Aquí hace falta atención: permita lo que de verdad pertenece al trabajo del servicio, y no todo seguido, o acabará con un perfil que lo permite todo y el sentido se pierde.
Y solo entonces:
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
Dónde ver las negativas
Todas las infracciones acaban en el diario del núcleo:
sudo journalctl -k | grep -i apparmor
sudo grep 'apparmor="DENIED"' /var/log/audit/audit.log
El segundo archivo existe si auditd está instalado, y con él los registros son bastante más detallados. Un registro de negativa muestra el nombre del perfil, la operación solicitada y la ruta a la que se accedía; con eso basta para saber si hay que corregir el perfil o alegrarse de que se disparara.
Un síntoma vale la pena recordarlo: un servicio se comporta de forma extraña —no lee una configuración, no escribe en un directorio, no abre un socket— mientras en sus propios registros aparece un error de «permiso denegado» con permisos manifiestamente correctos. Eso es casi siempre AppArmor, y lo primero es mirar el diario del núcleo.
Una medida práctica, no teórica
Un perfil para PHP-FPM o nginx se amortiza de forma concreta. Con el proceso confinado, un web shell que llegue al sitio no puede leer archivos del sistema, ni lanzar un intérprete, ni escribir fuera de los directorios permitidos. Un sitio comprometido sigue siendo un sitio comprometido en vez de convertirse en acceso a toda la máquina, y es precisamente ese salto el que constituye la mayor parte del daño.
Un orden razonable de adopción: primero un perfil para lo que mira a internet (servidor web, PHP-FPM), después para las bases de datos, luego según haga falta. No es necesario activarlo todo de golpe, y no existe un conjunto universal listo: un perfil depende de dónde viven sus archivos.
Qué comprobar con regularidad
Los perfiles vuelven al estado no confinado más a menudo de lo que parece: una actualización de paquete puede sustituir un archivo de perfil, una depuración manual deja un servicio en complain, y un servicio nuevo llega sin perfil alguno. Dos cifras son útiles: cuántos perfiles hay en enforce y cuántos procesos de red están sin restricciones. Un cambio en cualquiera de ellas merece conocerse. Cómo se ve eso reunido en una página lo muestra la demostración de abajo.