Gestión de espacios de nombres de usuario y SELinux en contenedores no rooteados

En este escenario, el usuario desea ejecutar un contenedor de base de datos MariaDB desde su directorio de inicio y desea montar un volumen desde su directorio de inicio en el contenedor. Aprendamos a administrar la seguridad al montar volúmenes en contenedores sin raíz.

Administrar SELinux

He hablado muchas veces sobre cómo SELinux es una excelente manera de confinar contenedores y lo fácil que es usarlo cuando se ejecuta un contenedor. motor de contenedor, Podman, lanza cada contenedor con una etiqueta SELinux de proceso única (generalmente container_t) y rotula todo el contenido del envase con una sola etiqueta (normalmente container_file_t). Tenemos reglas que establecen que container_t puede leer y escribir todo el contenido etiquetado container_file_t. Esta simple idea bloqueó las principales vulnerabilidades del sistema de archivos.

Todo funciona bien hasta que el usuario intenta un montaje de volumen. El problema con los volúmenes es que, por lo general, solo vinculan montajes en el host. Traen las etiquetas de , con las que la política de SELinux no permite que la etiqueta interactúe, y el contenedor explota. Esto no es un error; es una característica. Incluso si los usuarios montan volúmenes explícitamente, SELinux, de manera predeterminada, evitará todo acceso siguiendo la filosofía de "la seguridad nunca debe ser voluntaria".

En el primer intento, si el usuario prueba el siguiente comando:

$ podman run --rm -v $HOME/mysql-data:/var/lib/mysql/data -e MYSQL_USER=user -e MYSQL_PASSWORD=pass -e MYSQL_DATABASE=db -p 3306:3306 mariadb/server
Permission denied ...

Explota con permiso denegado. El usuario lee la página del manual y comprende que el problema es SELinux. El usuario ve que puede añadir un :Z al montar el volumen, lo que le indica a Podman que vuelva a etiquetar el contenido del volumen para que coincida con la etiqueta dentro del contenedor. Y el problema de SELinux está resuelto.

$ podman run --rm -v $HOME/mysql-data:/var/lib/mysql/data:Z -e MYSQL_USER=user -e MYSQL_PASSWORD=pass -e MYSQL_DATABASE=db -p 3306:3306 mariadb/server
Permission denied …

Vaya, triste sonido de trombón - SELinux está arreglado, pero ahora el usuario tiene otro problema.

espacio de nombre de usuario

Esta vez el problema es que el $HOME/mysql-data El directorio pertenece al usuario. En un blog anterior, hablé de cómo --user funciona en contenedores sin raíz. Expliqué que el usuario root de un contenedor sin root, por defecto, es el UID del usuario. Esto significa que los archivos que pertenecen al usuario dentro del contenedor pertenecen a la raíz dentro del contenedor. El problema aquí es que MariaDB necesita poseer el directorio de la base de datos y no se ejecuta como root dentro del contenedor. En su lugar, se ejecuta como usuario de MariaDB.

$ podman run -ti mariadb/server grep mysql /etc/passwd
mysql:x:999:999::/home/mysql:/bin/sh

Después de un pequeño trabajo de detective, el usuario descubre que el servidor MariaDB se está ejecutando como usuario 999. Por lo tanto, el usuario debe chown los datos mysql deben ser 999:999, para que MariaDB dentro del contenedor pueda leer/escribir la base de datos.

Ahora el usuario puede intentar la siguiente corrección:

chown 999:999 -R $HOME/mysql-data

Pero al usuario se le negará el permiso. Además, este es el par UID:GID incorrecto. Recuerde que el par UID:GID es relativo al espacio de nombres de usuario en el que el usuario ejecutará el contenedor. Ahora tenemos un gran problema matemático. Necesitamos ver el espacio de nombres de usuario con el que el usuario ejecutará el contenedor y luego agregar 999 al UID de inicio del rango: 1. Y espero que lo hayamos hecho bien.

Entonces el usuario podría intentar esto:

sudo chown CONTAINER999:CONTAINER999 -R $HOME/mysql-data

Una forma más fácil de manejar esta situación sería usar podman unshare. El comando unshare es un comando genial que se une al espacio de nombres del usuario sin ejecutar ningún contenedor.

Por ejemplo, el usuario puede ingresar:

podman unshare chown 999:999 -R $HOME/mysql-data

El usuario ahora está listo para ejecutar el contenedor sin root con el siguiente comando:

$ podman run --rm -v $HOME/mysql-data:/var/lib/mysql/data:Z -e MYSQL_USER=user -e MYSQL_PASSWORD=pass -e MYSQL_DATABASE=db -p 3306:3306 mariadb/server

Y Eureka! Eso funciona.

Conclusión

Ejecutar contenedores en un entorno sin raíz es muy seguro y la mayoría de los contenedores funcionarán de manera inmediata. Pero cuando empiezas a agregar --volumes, es posible que tenga problemas con algunos de los mecanismos de seguridad que protegen su host del contenedor. Comprender lo que está sucediendo le ahorrará mucho tiempo y molestias.

Artículos de interés

Subir