Por qué los procesos en contenedores Docker no deberían ejecutarse como raíz


Los procesos en un contenedor Docker no deben ejecutarse como root. Es más seguro ejecutar sus aplicaciones como un usuario no root que especifica como parte de su Dockerfile o cuando usa docker run. Esto minimiza el riesgo al presentar una superficie de ataque reducida para cualquier amenaza en su contenedor.

En este artículo, aprenderá sobre los peligros de ejecutar aplicaciones en contenedores como root. También verá cómo crear un usuario no raíz y configurar el espacio de nombres en situaciones en las que esto no es posible.

¿Por qué es peligroso ejecutar como raíz?

Los contenedores se ejecutan como raíz de forma predeterminada. El demonio Docker se ejecuta como root en su host y los contenedores en ejecución también serán root.

Aunque puede parecer que la raíz dentro del contenedor es un usuario independiente, en realidad es lo mismo que la cuenta raíz en su host. La separación solo la proporcionan los mecanismos de aislamiento de contenedores de Docker. No hay un límite físico fuerte; su contenedor es otro proceso ejecutado por el usuario root en el kernel de su host. Esto significa que una vulnerabilidad en su aplicación, el tiempo de ejecución de Docker o el kernel de Linux podría permitir a los atacantes salir del contenedor y realizar operaciones con privilegios de root en su máquina.

Hay algunas protecciones integradas que reducen el riesgo de que esto suceda. La raíz dentro del contenedor no tiene privilegios y tiene capacidades restringidas. Esto evita que el contenedor use los comandos de administración del sistema a menos que agregue capacidades manualmente o use el modo privilegiado cuando inicie sus contenedores.

A pesar de esta mitigación, permitir que las aplicaciones se ejecuten como raíz sigue siendo un peligro. Al igual que restringiría el uso de la raíz en un entorno tradicional, no es aconsejable usarlo innecesariamente dentro de sus contenedores. Estás proporcionando un entorno privilegiado que les da a los atacantes más puntos de apoyo en caso de que ocurra una infracción.

Ejecución de aplicaciones en contenedores como usuario no root

Es una buena práctica que las aplicaciones en contenedores se ejecuten como un usuario normal. La mayoría del software no necesita acceso a la raíz, por lo que cambiar el usuario proporciona una capa de defensa inmediata contra la ruptura del contenedor.

Debe crear una nueva cuenta de usuario como una de las etapas finales en su Dockerfile. Puedes lograr esto con el USER instrucción:

FROM base-image:latest
RUN apt install demo-package
USER demo-user:demo-group
ENTRYPOINT ["demo-binary"]

Los contenedores iniciados a partir de esta imagen se ejecutarán como demo-user. El usuario será miembro de la demo-group grupo. Puede omitir el nombre del grupo si no necesita que el usuario esté en un grupo:

USER demo-user

Puede especificar una ID de usuario (UID) y una ID de grupo (GID) en lugar de nombres:

USER 950:950

La asignación de un UID y GID conocido suele ser la forma más segura de proceder. Evita que el usuario del contenedor sea asignado a una cuenta de host con privilegios excesivos.

USER a menudo se especifica como la penúltima etapa en un Dockerfile. Esto significa que aún puede ejecutar operaciones que requieren root antes en la creación de la imagen. los apt install instrucción en el ejemplo anterior tiene una necesidad legítima de root. Si el USER la instrucción se colocó encima de él, apt se ejecutaría como demo-user que carecería de los permisos necesarios. Como las instrucciones de Dockerfile solo se aplican a las compilaciones de imágenes, no a los contenedores en ejecución, es seguro dejar el cambio de usuario para más adelante en su Dockerfile.

Cambiar el usuario que ejecuta su contenedor puede requerir que actualice los permisos en los archivos y carpetas a los que accede. Establezca la propiedad en cualquier ruta que utilizará su aplicación:

COPY initial-config.yaml /data/config.yaml

USER demo-user:demo-group
RUN chown demo-user:demo-group /data

En este ejemplo el /data el directorio debe ser propiedad de demo-user para que la aplicación pueda realizar cambios en su archivo de configuración. El anterior COPY declaración habrá copiado el archivo como raíz. Una forma abreviada está disponible usando el --chown bandera con copy:

COPY --chown=demo-user:demo-group initial-config.yaml /data/config.yaml

Cambiar el usuario al iniciar un contenedor

Si bien puede cambiar fácilmente el usuario en sus propios Dockerfiles, muchas aplicaciones de terceros continúan ejecutándose como raíz. Puede reducir el riesgo asociado con el uso de estos configurando el --user marca cada vez que llamas docker run. Esto anula el conjunto de usuarios en el Dockerfile de la imagen.

$ docker run -d --user demo-user:demo-group demo-image:latest
$ docker run -d --user demo-user demo-image:latest
$ docker run -d --user 950:950 demo-image:latest

los --user flag ejecuta el proceso del contenedor como el usuario especificado. Es menos seguro que el Dockerfile USER instrucción porque tienes que aplicarla individualmente a cada docker run dominio. Una mejor opción para las imágenes de uso regular es crear su propia imagen derivada que pueda establecer una nueva cuenta de usuario:

FROM image-that-runs-as-root:latest
USER demo-user
$ docker build . -t image-that-now-runs-as-non-root:latest

Cambiar el usuario de una imagen de terceros puede causar problemas: si el contenedor espera ejecutarse como root o necesita acceder a las rutas del sistema de archivos propiedad del root, verá errores mientras usa la aplicación. Puede intentar cambiar manualmente los permisos en las rutas que causan problemas. Como alternativa, verifique si el proveedor tiene un método compatible para ejecutar la aplicación con una cuenta de usuario sin privilegios.

Manejo de aplicaciones que tienen que ejecutarse como raíz

El espacio de nombres de usuario es una técnica para tratar con aplicaciones que necesitan algunos privilegios de root. Le permite asignar la raíz dentro de un contenedor a un usuario no raíz en su host. La raíz simulada dentro del contenedor tiene los privilegios que necesita, pero una ruptura no proporcionará acceso de raíz al host.

La reasignación de espacios de nombres se activa agregando un userns-remap campo a tu /etc/docker/daemon.json expediente:


    "userns-remap": "default"

Usando default como el valor para userns-remap indica a Docker que cree automáticamente un nuevo usuario en su host llamado dockremap. La raíz dentro de los contenedores se asignará de nuevo a dockremap en su anfitrión. Opcionalmente, puede especificar un usuario y grupo existente en su lugar, utilizando una combinación de nombre de usuario/grupo o UID/GID:


    "userns-remap": "demo-user"

Reinicie el demonio de Docker después de aplicar su cambio:

$ sudo service docker restart

si estás usando nsuser-remap: defaultla dockremap el usuario ahora debería existir en su host:

$ id dockremap

uid=140(dockremap) gid=119(dockremap) groups=119(dockremap)

El usuario también debe aparecer en el /etc/subuid y /etc/subgid archivos de ID subordinados:

$ dockremap:231500:65535

Al usuario se le ha asignado un rango de 65 535 ID subordinados a partir de 231500. Dentro del espacio de nombres de usuario, ID 231500 está asignado a 0, convirtiéndolo en el usuario raíz en sus contenedores. Al ser un UID de número alto, 231500 no tiene privilegios en el host, por lo que los ataques de ruptura de contenedores no podrán infligir tanto daño.

Todos los contenedores que inicie se ejecutarán utilizando el espacio de nombres de usuario reasignado a menos que opte por no hacerlo con docker run --userns=host. El mecanismo funciona mediante la creación de directorios con espacios de nombres dentro /var/lib/docker que son propiedad del UID y GID subordinado del usuario con espacio de nombres:

$ sudo ls -l /var/lib/docker/231500.231500

total 14
drwx------ 5 231500 231500 13 Jul 22 19:00 aufs
drwx------ 3 231500 231500 13 Jul 22 19:00 containers
...

El espacio de nombres de usuario es una forma efectiva de aumentar el aislamiento del contenedor, evitar rupturas y preservar la compatibilidad con aplicaciones que necesitan privilegios de raíz. Sin embargo, existen algunas ventajas y desventajas: la característica funciona mejor en una instancia nueva de Docker, los volúmenes montados desde el host deben tener sus permisos ajustados y algunos controladores de almacenamiento externo no admiten el mapeo de usuarios en absoluto. Debe revisar la documentación antes de adoptar esta opción.

Resumen

Ejecutar aplicaciones en contenedores como raíz es un riesgo de seguridad. Aunque es fácil pasarlo por alto, el aislamiento proporcionado por los contenedores no es lo suficientemente sólido como para separar por completo a los usuarios del kernel de los usuarios de los contenedores. La raíz en el contenedor es lo mismo que la raíz en su host, por lo que un compromiso exitoso podría proporcionar el control de su máquina.

Como autor de una imagen, debe incluir la USER instrucción en su Dockerfile para que su aplicación se ejecute sin root. Los usuarios de imágenes pueden anular esto con docker run --user para asignar un UID y GID específico. Esto ayuda a mitigar los casos en los que la imagen normalmente usa la raíz.

Puede reforzar aún más la seguridad eliminando todas las capacidades del contenedor usando --cap-drop=ALLluego incluir en la lista blanca aquellos que son necesarios con --cap-add banderas La combinación de estas técnicas ejecutará su aplicación como un usuario no root con el conjunto mínimo de privilegios que necesita, mejorando su postura de seguridad.





Source link-39