Docker SecDevOps y las Linux Capabilites
Hace unos días, nuestro buen amigo Pablo González nos explicó en este artículo cómo se puede realizar una escalada de privilegios utilizando las Linux Capabilities. En dicho artículo comentaba la importancia de su configuración y control para realizar una correcta fortificación de los entornos GNU/Linux. Pues bien, en el mundo de los contenedores Docker las Linux Capabilities son también muy importantes a la hora de gestionar correctamente la seguridad, tanto del contenedor como del host.
Figura 1: Docker SecDevOps y las Linux Capabilites
Ya sabemos que, por defecto, cuando levantamos un contenedor Docker, éste se ejecuta como root. Pero claro, todos sabemos que esta práctica no es una buena idea, sobre todo servicios que recibe peticiones ya sean por parte de usuarios o provenientes de otras fuentes. Por cierto, si quieres aprender las bases de Docker y el mundo que les rodea, tenemos este libro en la editorial 0xWord para ayudarte a comprender este fascinante (y cada vez más demandado) mundo de los contenedores:
Figura 2: Libro de Docker:SecDevOps |
También es importante mencionar, que, aunque un contenedor ejecutado como root, no tiene los mismos privilegios que el usuario root del host. Esto es porque por defecto, los contenedores Docker se ejecutan con un número limitado de capacidades (Linux capabilities), concretamente con las siguientes:
• AUDIT_WRITE • CHOWN • DAC_OVERRIDE • FOWNER • UID • FSETID • KILL • MKNOD • NET_BIND_SERVICE • NET_RAW • SETFCAP • SETGID • SETPCAP • SETUID • SYS_CHROOTEsto también lo podemos comprobar arrancando un contenedor, conectarnos a una shell y listando las capacidades. Para ver este ejemplo usaremos una imagen Ubuntu e instalaremos el paquete libcap2-bin, el cual contiene utilidades para trabajar con capacidades:
docker run -it ubuntu root@a8761683eb71:/# apt update Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [109 kB] Get:2 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB] ... ... root@a8761683eb71:/# apt install -y libcap2-bin ... ... root@a8761683eb71:/# grep Cap /proc/$BASHPID/status CapInh: 00000000a80425fb CapPrm: 00000000a80425fb CapEff: 00000000a80425fb CapBnd: 00000000a80425fb CapAmb: 0000000000000000 ... ... root@a8761683eb71:/# capsh --decode=00000000a80425fb 0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid, cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod, cap_audit_write,cap_setfcapSi comparamos la lista de capacidades devuelta por el comando capsh, vemos que corresponde a la lista mostrada anteriormente. Además de dichas capacidades, Docker permite añadir otras capacidades dentro de la siguiente lista:
• AUDIT_CONTROL • AUDIT_READ • BLOCK_SUSPEND • BPF • CHECKPOINT_RESTORE • DAC_READ_SEARCH • IPC_LOCK • IPC_OWNER • LEASE • LINUX_IMMUTABLE • MAC_ADMIN • MAC_OVERRIDE • NET_ADMIN • NET_BROADCAST • PERFMON • SYS_ADMIN • SYS_BOOT • SYS_MODULE • SYS_NICE • SYS_PACCT • SYS_PTRACE • SYS_RAWIO • SYS_RESOURCE • SYS_TIME • SYS_TTY_CONFIG • WAKE_ALARMPara saber qué tipo de privilegios proveen estas capacidades, puedes consultar la documentación de Docker o directamente la documentación de Linux. Si miras la documentación de Linux, verás que el nombre de las capacidades tienen el prefijo CAP_, mientras que para el uso de éstas en Docker, se omite dicho prefijo, así la capacidad CAP_CHOWN, referenciaría simplemente como CHOWN en Docker.
(Revisada y Ampliada) de Carlos Álvarez y Pablo González en 0xWord
Para jugar con las capacidades en Docker lo haremos a través de las opciones --cap-add y --cap-drop. Por ejemplo, si arrancamos un contenedor y le quitamos la capacidad de cambiar el propietario de un fichero (o directorio):
docker run -it --cap-drop=CHOWN ubuntu root@4c385a7c43c2:/# chown nobody tmp chown: changing ownership of 'tmp': Operation not permitted root@4c385a7c43c2:/# id uid=0(root) gid=0(root) groups=0(root)Como podemos ver, incluso siendo root no tenemos el permiso para cambiar el propietario de un fichero. Recuerda que en Linux, todo es un fichero, y en el libro de Linux Exploiting le sacan buen partido a esto.
Figura 4: Linux Exploiting |
Otro ejemplo, si le quitamos la capacidad de NET_RAW al contenedor, no podríamos por ejemplo hacer ping:
docker run -it --cap-drop=NET_RAW busybox / # ping google.com PING google.com (172.217.15.110): 56 data bytes ping: permission denied (are you root?) / # id uid=0(root) gid=0(root) groups=10(wheel)Como buena práctica de seguridad sería el quitar todas las capacidades de un contenedor, para ello, Docker provee de la opción ALL, para referenciar a todas las capacidades:
docker run -it --cap-drop=ALL ubuntu root@88c31bcf9d36:/# apt update E: setgroups 65534 failed - setgroups (1: Operation not permitted) E: setegid 65534 failed - setegid (1: Operation not permitted) ... ... root@88c31bcf9d36:/# id uid=0(root) gid=0(root) groups=0(root)Con eso le quitaríamos todos los permisos al usuario, incluso root. Como se puede ver en el ejemplo, root ni siquiera podría instalar software nuevo, hacer ping, modificar el propietario de un fichero, etcétera. Por supuesto, el ejecutar el contenedor como NO root es también una buena práctica y un de las principales acciones que uno debería tomar para proteger un contenedor. Lo ideal sería ejecutar el contenedor con un usuario sin ninguna capacidad, y si es necesario, añadir únicamente las capacidades que se necesiten. Si usas docker-compose, el equivalente sería:
version: "3.9" services: miservicio: ... cap_drop: - ALL cap_add: - NET_ADMIN - SYS_ADMIN ...Y en Kubernetes, esto se definiría dentro del contexto de seguridad del pod o del contenedor o contenedores:
apiVersion: v1 kind: Pod metadata: name: capacidades-ejemplo spec: containers: - name: capacidades-ejemplo image: mi-imagen securityContext: capabilities: drop: - ALL add: - NET_ADMIN - SYS_TIME ... ...Existen muchas otras buenas prácticas de seguridad en relación con proteger tus contenedores e imágenes Docker. Aquí sólo hemos visto un poco lo relacionado al tema de las capacidades de Linux. Volveremos a hablar de la importancia de la seguridad tanto en contenedores como en Kubernetes. Así que atentos ;)
Happy Hacking Hackers!!!
Autores:
Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps", también de "Machine Learning aplicado a la Ciberseguridad” además del blog CyberHades. Puedes contactar con Fran Ramirez en MyPublicInbox.
Rafael Troncoso (@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" además del blog CyberHades. Puedes contactar con Rafael Troncoso en MyPublicInbox.
Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps", también de "Machine Learning aplicado a la Ciberseguridad” además del blog CyberHades. Puedes contactar con Fran Ramirez en MyPublicInbox.
Contactar con Fran Ramírez en MyPublicInbox |
Rafael Troncoso (@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" además del blog CyberHades. Puedes contactar con Rafael Troncoso en MyPublicInbox.
Contactar con Rafael Troncoso en MyPublicInbox |
No hay comentarios:
Publicar un comentario