Perfiles de seguridad AppArmor para Docker
AppArmor (Application Armor) es un módulo de seguridad de Linux que protege a un sistema operativo y sus aplicaciones de amenazas de seguridad. Para usarlo, un administrador del sistema asocia un perfil de seguridad de AppArmor con cada programa. Docker espera encontrar una política de AppArmor cargada y aplicada.
Docker genera y carga automáticamente un perfil predeterminado para los contenedores llamado docker-default. El binario de Docker genera este perfil en tmpfs y luego lo carga en el kernel.
NoteEste perfil se utiliza en los contenedores, no en el demonio de Docker.
Existe un perfil para el demonio de Docker Engine, pero actualmente no se instala con los paquetes deb. Si tienes interés en el código fuente del perfil del demonio, se encuentra en contrib/apparmor en el repositorio de código fuente de Docker Engine.
Entender las políticas
El perfil docker-default es el predeterminado para ejecutar contenedores. Protege de forma moderada a la vez que proporciona una amplia compatibilidad de aplicaciones. El perfil se genera a partir de la siguiente plantilla.
Cuando ejecutas un contenedor, este utiliza la política docker-default a menos que la anules con la opción security-opt. Por ejemplo, lo siguiente especifica explícitamente la política predeterminada:
$ docker run --rm -it --security-opt apparmor=docker-default hello-world
Cargar y descargar perfiles
Para cargar un nuevo perfil en AppArmor para usarlo con contenedores:
$ apparmor_parser -r -W /ruta/a/tu_perfil
Luego, ejecuta el perfil personalizado con --security-opt:
$ docker run --rm -it --security-opt apparmor=tu_perfil hello-world
Para descargar un perfil de AppArmor:
# descargar el perfil
$ apparmor_parser -R /ruta/al/perfil
Recursos para escribir perfiles
La sintaxis para la búsqueda de archivos (globbing) en AppArmor es un poco diferente a la de algunas otras implementaciones de globbing. Te sugerimos que eches un vistazo a algunos de los siguientes recursos con respecto a la sintaxis de los perfiles de AppArmor.
Perfil de ejemplo de Nginx
En este ejemplo, creas un perfil de AppArmor personalizado para Nginx. A continuación se muestra el perfil personalizado.
#include <tunables/global>
profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network inet tcp,
network inet udp,
network inet icmp,
deny network raw,
deny network packet,
file,
umount,
deny /bin/** wl,
deny /boot/** wl,
deny /dev/** wl,
deny /etc/** wl,
deny /home/** wl,
deny /lib/** wl,
deny /lib64/** wl,
deny /media/** wl,
deny /mnt/** wl,
deny /opt/** wl,
deny /proc/** wl,
deny /root/** wl,
deny /sbin/** wl,
deny /srv/** wl,
deny /tmp/** wl,
deny /sys/** wl,
deny /usr/** wl,
audit /** w,
/var/run/nginx.pid w,
/usr/sbin/nginx ix,
deny /bin/dash mrwklx,
deny /bin/sh mrwklx,
deny /usr/bin/top mrwklx,
capability chown,
capability dac_override,
capability setuid,
capability setgid,
capability net_bind_service,
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir)
# deny write to files not in /proc/<number>/** or /proc/sys/**
deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,
deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/
deny @{PROC}/sysrq-trigger rwklx,
deny @{PROC}/mem rwklx,
deny @{PROC}/kmem rwklx,
deny @{PROC}/kcore rwklx,
deny mount,
deny /sys/[^f]*/** wklx,
deny /sys/f[^s]*/** wklx,
deny /sys/fs/[^c]*/** wklx,
deny /sys/fs/c[^g]*/** wklx,
deny /sys/fs/cg[^r]*/** wklx,
deny /sys/firmware/** rwklx,
deny /sys/kernel/security/** rwklx,
}
Guarda el perfil personalizado en el disco en el archivo
/etc/apparmor.d/containers/docker-nginx.La ruta del archivo en este ejemplo no es un requisito. En producción, puedes usar otra.
Carga el perfil.
$ sudo apparmor_parser -r -W /etc/apparmor.d/containers/docker-nginxEjecuta un contenedor con el perfil.
Para ejecutar nginx en modo desasociado (detached):
$ docker run --security-opt "apparmor=docker-nginx" \ -p 80:80 -d --name apparmor-nginx nginxEntra al contenedor en ejecución (exec).
$ docker container exec -it apparmor-nginx bashPrueba algunas operaciones para verificar el perfil.
root@6da5a2a930b9:~# ping 8.8.8.8 ping: Lacking privilege for raw socket. root@6da5a2a930b9:/# top bash: /usr/bin/top: Permission denied root@6da5a2a930b9:~# touch ~/thing touch: cannot touch 'thing': Permission denied root@6da5a2a930b9:/# sh bash: /bin/sh: Permission denied root@6da5a2a930b9:/# dash bash: /bin/dash: Permission denied
Acabas de desplegar un contenedor protegido con un perfil apparmor personalizado.
Depurar AppArmor
Puedes usar dmesg para depurar problemas y aa-status para comprobar los perfiles cargados.
Usar dmesg
Aquí tienes algunos consejos útiles para depurar cualquier problema que puedas enfrentar con respecto a AppArmor.
AppArmor envía mensajes bastante detallados a dmesg. Por lo general, una línea de AppArmor se parece a la siguiente:
[ 5442.864673] audit: type=1400 audit(1453830992.845:37): apparmor="ALLOWED" operation="open" profile="/usr/bin/docker" name="/home/jessie/docker/man/man1/docker-attach.1" pid=10923 comm="docker" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0En el ejemplo anterior, puedes ver profile=/usr/bin/docker. Esto significa que el usuario tiene cargado el perfil de docker-engine (demonio de Docker Engine).
Mira otra línea de registro:
[ 3256.689120] type=1400 audit(1405454041.341:73): apparmor="DENIED" operation="ptrace" profile="docker-default" pid=17651 comm="docker" requested_mask="receive" denied_mask="receive"Esta vez, el perfil es docker-default, que se ejecuta en los contenedores de forma predeterminada a menos que esté en modo privileged (privilegiado). Esta línea muestra que apparmor ha denegado ptrace en el contenedor. Esto es exactamente lo esperado.
Usar aa-status
Si necesitas comprobar qué perfiles están cargados, puedes usar aa-status. La salida se parece a:
$ sudo aa-status
apparmor module is loaded.
14 profiles are loaded.
1 profiles are in enforce mode.
docker-default
13 profiles are in complain mode.
/usr/bin/docker
/usr/bin/docker///bin/cat
/usr/bin/docker///bin/ps
/usr/bin/docker///sbin/apparmor_parser
/usr/bin/docker///sbin/auplink
/usr/bin/docker///sbin/blkid
/usr/bin/docker///sbin/iptables
/usr/bin/docker///sbin/mke2fs
/usr/bin/docker///sbin/modprobe
/usr/bin/docker///sbin/tune2fs
/usr/bin/docker///sbin/xtables-multi
/usr/bin/docker///sbin/zfs
/usr/bin/docker///usr/bin/xz
38 processes have profiles defined.
37 processes are in enforce mode.
docker-default (6044)
...
docker-default (31899)
1 processes are in complain mode.
/usr/bin/docker (29756)
0 processes are unconfined but have a profile defined.
La salida anterior muestra que el perfil docker-default que se ejecuta en varios PID de contenedores está en modo enforce. Esto significa que AppArmor está bloqueando y auditando activamente en dmesg cualquier cosa fuera de los límites del perfil docker-default.
La salida anterior también muestra que el perfil /usr/bin/docker (demonio de Docker Engine) se está ejecutando en modo complain. Esto significa que AppArmor solo registra en dmesg la actividad fuera de los límites del perfil. (Excepto en el caso de Ubuntu Trusty, donde se imponen algunos comportamientos interesantes).
Contribuir al código de AppArmor de Docker
Los usuarios avanzados y los administradores de paquetes pueden encontrar un perfil para /usr/bin/docker (demonio de Docker Engine) en contrib/apparmor en el repositorio de código fuente de Docker Engine.
El perfil docker-default para contenedores vive en profiles/apparmor.