¿Qué es un contenedor LXC sin privilegios?

20

¿Qué significa si un contenedor de Linux (contenedor LXC) se llama "sin privilegios"?

0xC0000022L
fuente

Respuestas:

20

Los contenedores LXC sin privilegios son los que utilizan espacios de nombres de usuario ( ). Es decir, una característica del kernel que permite asignar un rango de UID en el host en un espacio de nombres dentro del cual un usuario con UID 0 puede existir nuevamente.

Contrariamente a mi percepción inicial de los contenedores LXC no privilegiados por un tiempo, esto no significa que el contenedor deba ser propiedad de un usuario host no privilegiado. Esa es solo una posibilidad.

Relevante es:

  1. que se define un rango de UID y GID subordinados para el usuario host ( usermod [-v|-w|--add-sub-uids|--add-sub-gids])
  2. ... y que este rango está mapeado en la configuración del contenedor ( lxc.id_map = ...)

Por lo tanto, incluso rootpuede poseer contenedores sin privilegios, ya que los UID efectivos de los procesos de contenedor en el host terminarán dentro del rango definido por la asignación.

Sin embargo, rootdebe definir primero los ID subordinados. A diferencia de los usuarios creados a través de adduser, rootno tendrá un rango de ID subordinados definidos por defecto.

También tenga en cuenta que el rango completo que proporciona está a su disposición, por lo que podría tener 3 contenedores con las siguientes líneas de configuración (solo se muestra la asignación de UID):

  1. lxc.id_map = u 0 100000 100000
  2. lxc.id_map = u 0 200000 100000
  3. lxc.id_map = u 0 300000 100000

suponiendo que rootposee los UID subordinados entre 100000 y 400000. Toda la documentación que encontré sugiere usar 65536 ID subordinados por contenedor, aunque algunos usan 100000 para que sea más legible para los humanos.

En otras palabras: no tiene que asignar el mismo rango a cada contenedor.

Con más de 4 mil millones (~ 2^32) posibles ID subordinados, eso significa que puede ser generoso al tratar los rangos subordinados con sus usuarios anfitriones.

Contenedor sin privilegios propiedad y ejecutado por root

Frotar eso de nuevo. Un invitado LXC sin privilegios no necesita ser ejecutado por un usuario sin privilegios en el host.

Configurar su contenedor con un mapeo UID / GID subordinado como este:

lxc.id_map = u 0 100000 100000
lxc.id_map = g 0 100000 100000

donde el usuario rooten el host posee ese rango de ID subordinado, le permitirá limitar a los invitados aún mejor.

Sin embargo, hay una ventaja adicional importante en este escenario (y sí, he verificado que funciona): puede iniciar automáticamente su contenedor al iniciar el sistema.

Por lo general, al buscar información sobre LXC en la web, se le informará que no es posible iniciar automáticamente un invitado LXC sin privilegios. Sin embargo, eso solo es cierto de manera predeterminada para aquellos contenedores que no están en el almacenamiento de todo el sistema para contenedores (generalmente algo así como /var/lib/lxc). Si lo son (lo que generalmente significa que fueron creados por root y son iniciados por root), es una historia completamente diferente.

lxc.start.auto = 1

hará el trabajo bastante bien, una vez que lo coloque en la configuración de su contenedor.

Obtención de permisos y configuración correctos

Luché un poco con esto, así que agrego una sección aquí.

Además del fragmento de configuración incluido a través del lxc.includecual generalmente lleva el nombre /usr/share/lxc/config/$distro.common.conf(donde $distroestá el nombre de una distribución), debe verificar si también hay un /usr/share/lxc/config/$distro.userns.confen su sistema e incluirlo también. P.ej:

lxc.include = /usr/share/lxc/config/ubuntu.common.conf
lxc.include = /usr/share/lxc/config/ubuntu.userns.conf

Además, agregue las asignaciones de ID subordinadas:

lxc.id_map = u 0 100000 65535
lxc.id_map = g 0 100000 65535

lo que significa que el UID del host 100000 está root dentro del espacio de nombres de usuario del invitado LXC.

Ahora asegúrese de que los permisos sean correctos. Si el nombre de su invitado se almacenara en la variable de entorno $lxcguest, ejecutaría lo siguiente:

# Directory for the container
chown root:root $(lxc-config lxc.lxcpath)/$lxcguest
chmod ug=rwX,o=rX $(lxc-config lxc.lxcpath)/$lxcguest
# Container config
chown root:root $(lxc-config lxc.lxcpath)/$lxcguest/config
chmod u=rw,go=r $(lxc-config lxc.lxcpath)/$lxcguest/config
# Container rootfs
chown 100000:100000 $(lxc-config lxc.lxcpath)/$lxcguest/rootfs
chmod u=rwX,go=rX $(lxc-config lxc.lxcpath)/$lxcguest/rootfs

Esto debería permitirle ejecutar el contenedor después de que su primer intento haya dado algunos errores relacionados con los permisos.

0xC0000022L
fuente
44
Buena respuesta, pero lxcno es una necesidad para este tipo de cosas. Puede crear un contenedor de espacio de nombres de cualquier tipo utilizando la util-linuxherramienta unshare. Puede ingresar dicho contenedor utilizando la util-linuxherramienta nsenter. La última herramienta también le permite agregar procesos en ejecución a un contenedor ya creado sin él. El soporte de espacio de nombres se implementa en el núcleo.
mikeserv
44
@mikeserv: ¿quiere decir que no necesita LXC para hacer uso de los usuarios ? Lo sabía. También sé que Docker ahora tiene su propia biblioteca haciendo uso de estas instalaciones. Pero, ¿cómo podría contener un sistema completo en contenedores sin la ayuda de las instalaciones que ofrece LXC? ¿Y por qué lo harías? Me refiero a contener una sola aplicación y combinarlo con chrootesto puede ayudar, pero LXC combina varios espacios de nombres (UTS, montaje, etc.) para contener todo el sistema.
0xC0000022L
2
Bueno ... Como dije, unshareya lo hace admirablemente para cualquiera / todos los diversos espacios de nombres, e incluso le conseguirá una /procmontura privada y separada con un solo interruptor de cli. Si su aplicación individual es inity chrootes, initramfsentonces obtiene un contenedor completo en segundos.
mikeserv
0

Durante el seguimiento en 0xC0000022L, cuya solución trabajado bien para mí, escribí una increase-uid-gid.pl script en Perl para automatizar la propiedad necesarios cambios requeridos modo que los archivos dentro de los contenedores LXC se asignan correctamente.

Sin ella, con esta configuración propuesta, un archivo dentro del contenedor LXC rootfs perteneciente a 0 / root en el host principal, dentro del contenedor LXC mismo, se asignará a 65534 / nobody. Para ser mapeado a 0 / root dentro del contenedor LXC, deben pertenecer a 100000 en el host.

Esto se describe aquí https://yeupou.wordpress.com/2017/06/23/setting-up-lxc-containers-with-mapped-giduid/ y el script se puede obtener directamente en gitlab https://gitlab.com /yeupou/stalag13/blob/master/usr/local/bin/increase-uid-gid.pl

yeupou
fuente