Uno de los temas más consultados por las personas que trabajan en tecnologías de contenedores upstream es la ejecución de Podman dentro de un contenedor. Históricamente, la mayor parte de esto ha estado relacionado con Docker en Docker (DIND), pero ahora, la gente también quiere ejecutar Podman en Podman (PINP) o Podman en Docker (PIND).
Pero Podman se puede ejecutar de múltiples maneras, con y sin raíces. Terminamos con personas que desean ejecutar varias combinaciones de Podman rootful y rootless:
- Rootful Podman en Rootful Podman
- Podman desarraigado en Podman arraigado
- Podman arraigado en Podman desarraigado
- Podman desarraigado en Podman desarraigado
Te haces una idea.
Este blog intentará cubrir cada combinación, comenzando con una discusión sobre los privilegios. Comenzaremos con el escenario PINP aquí en la primera parte. En la segunda parte de la serie, cubriremos un terreno similar pero lo haremos dentro del contexto de Kubernetes. Asegúrese de leer ambos artículos para obtener una imagen completa.
Los motores de contenedores requieren privilegios
Para ejecutar un motor de contenedor como Podman dentro de un contenedor, lo primero que debe comprender es que necesita una cantidad considerable de privilegios.
- Los contenedores requieren varios UID. La mayoría de las imágenes de contenedor necesitan más de un UID para funcionar. Por ejemplo, podría tener una imagen con la mayoría de los archivos propiedad de root, pero algunos propiedad del usuario apache (UID=60).
- Los motores de contenedores montan sistemas de archivos y usan el clon de llamada del sistema para crear espacios de nombres de usuario.
Nota:es posible que necesite una versión más reciente de Podman. Los ejemplos de este blog se ejecutaron con Podman 3.2.
Nuestra imagen de prueba
Para los ejemplos de este blog, usaremos quay.io/podman/stable
image, que se creó con la idea de encontrar la mejor manera de ejecutar Podman dentro de un contenedor. Puede examinar cómo construimos esta imagen desde Dockerfile y containers.conf
imagen en el repositorio de github.com.
# stable/Dockerfile
#
# Build a Podman container image from the latest
# stable version of Podman on the Fedoras Updates System.
# https://bodhi.fedoraproject.org/updates/?search=podman
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM registry.fedoraproject.org/fedora:latest
# Don't include container-selinux and remove
# directories used by yum that are just taking
# up space.
RUN dnf -y update; yum -y reinstall shadow-utils; \
yum -y install podman fuse-overlayfs --exclude container-selinux; \
rm -rf /var/cache /var/log/dnf* /var/log/yum.*
RUN useradd podman; \
echo podman:10000:5000 > /etc/subuid; \
echo podman:10000:5000 > /etc/subgid;
VOLUME /var/lib/containers
VOLUME /home/podman/.local/share/containers
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
RUN chown podman:podman -R /home/podman
# chmod containers.conf and adjust storage.conf to enable Fuse storage.
RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers /var/lib/shared/vfs-images /var/lib/shared/vfs-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock; touch /var/lib/shared/vfs-images/images.lock; touch /var/lib/shared/vfs-layers/layers.lock
ENV _CONTAINERS_USERNS_CONFIGURED=""
Examinemos el Dockerfile.
FROM registry.fedoraproject.org/fedora:latest
# Don't include container-selinux and remove
# directories used by yum that are just taking
# up space.
RUN dnf -y update; yum -y reinstall shadow-utils; \
yum -y install podman fuse-overlayfs --exclude container-selinux; \
rm -rf /var/cache /var/log/dnf* /var/log/yum.*
Primero extraiga la última versión de Fedora y luego actualice a los últimos paquetes. Tenga en cuenta que reinstala shadow-utils
, ya que hay un problema conocido en shadow-utils
instalar en la imagen de Fedora donde el filecaps
en newsubuid
y newsubgid
no están establecidos. Reinstalando shadow-utils
soluciona el problema A continuación, instale Podman y fuse-overlayfs
. No instalamos container-selinux
porque no se necesita dentro del contenedor.
RUN useradd podman; \
echo podman:10000:5000 > /etc/subuid; \
echo podman:10000:5000 > /etc/subgid;
Luego creo un usuario podman
y configure el /etc/subuid
y /etc/subgid
archivos para usar 5000 UID. Esto se usa para configurar el espacio de nombres de usuario dentro del contenedor. 5000 es un número arbitrario y potencialmente demasiado pequeño. Elegimos este número porque es más pequeño que los 65k asignados a usuarios sin raíz. Si solo estuviera ejecutando el contenedor como root, 65k habría sido un número mejor.
VOLUME /var/lib/containers
VOLUME /home/podman/.local/share/containers
Dado que podemos ejecutar contenedores rootfull y rootless con esta imagen, creamos dos volúmenes. Rootfull Podman usa /var/lib/containers
para su almacenamiento en contenedores y usos sin raíz /home/podman/.local/share/containers
. El kernel a menudo niega superposición sobre superposición, por lo que esto crea volúmenes no superpuestos para ser utilizados dentro del contenedor.
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
He preconfigurado dos containers.conf
archivos para asegurarse de que los contenedores se ejecuten más fácilmente en cada modo.
La imagen está configurada para ejecutarse con fuse-overlayfs de forma predeterminada. En ciertos casos, puede ejecutar el sistema de archivos de superposición del núcleo para el modo raíz, y pronto podrá hacerlo en modo sin raíz. Sin embargo, por ahora, usamos fuse-overlayfs como nuestro contenedor de almacenamiento dentro del contenedor. Otras personas han usado el controlador de almacenamiento VFS, pero este no es tan eficiente.
La bandera --privilegiada
La forma más fácil de ejecutar Podman dentro de un contenedor es usar el --privileged
bandera.
Podman rootful en Podman rootful con --privileged
# podman run --privileged quay.io/podman/stable podman run ubi8 echo hello
Resolved "ubi8-minimal" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
Trying to pull registry.access.redhat.com/ubi8:latest...
Getting image source signatures
Copying blob sha256:a591faa84ab05242a17131e396a336da172b0e1ec66d921c9f130b7c4c24586d
Copying blob sha256:76b9354adec626b01ffb0faae4a217cebd616661fd90c4b54ba4415f53392fb8
Copying config sha256:dc080723f596f2407300cca2c19a17accad89edcf39f7b8b33e6472dd41e30f1
Writing manifest to image destination
Storing signatures
hello
Para ahorrar tiempo, ya que haré muchos experimentos, creé un directorio en mi host ./mycontainers
, que montaré en volumen en el contenedor para usar y no tener que extraer la imagen cada vez.
# podman run --privileged -v ./mycontainers:/var/lib/containers quay.io/podman/stable podman run ubi8 echo hello
hello
Podman desarraigado en Podman rootful con --privileged
El quay.io/podman/stable
la imagen se configura con un podman usuario que puede usar para ejecutar contenedores sin raíz.
# podman run --user podman --privileged quay.io/podman/stable podman run ubi8 echo hello
Resolved "ubi8" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
...
hello
Tenga en cuenta que en este caso, el Podman que se ejecuta dentro del contenedor se ejecuta como el usuario podman . Esto se debe a que el Podman en contenedor usa el espacio de nombres de usuario para crear un contenedor confinado dentro del contenedor privilegiado.
Ejecutar Podman sin raíz en Docker con --privileged
Similar a Rootful Podman, también puede ejecutar Podman sin root dentro de Docker con --privileged
opción.
# docker run --privileged quay.io/podman/stable podman run ubi8 echo hello
Podman sin raíz con Docker
# docker run --user podman --privileged quay.io/podman/stable podman run ubi8 echo hello
Resolved "ubi8" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
...
hello
¿Podemos hacer esto de forma más segura?
Tenga en cuenta que aunque ejecutamos los contenedores externos --privileged
arriba, los contenedores internos están funcionando en modo bloqueado. El Podman desarraigado que corre dentro del contenedor está realmente bloqueado y tendría muchas dificultades para escapar. Dado eso, no soy fanático de usar --privileged
bandera. Creo que podemos hacerlo mejor desde una perspectiva de seguridad.
Ejecutar sin la marca --privileged
Veamos cómo podemos eliminar el --privileged
bandera para mayor seguridad.
Podman rootful en Podman rootful sin --privileged
# podman run --cap-add=sys_admin,mknod --device=/dev/fuse --security-opt label=disable quay.io/podman/stable podman run ubi8-minimal echo hello
hello
Podemos eliminar el --privileged
marcar desde rootful Podman pero aún tengo que deshabilitar algunas funciones de seguridad para que Rootful Podman dentro del contenedor funcione.
- Capacidades:
--cap-add=sys_admin,mknod
Necesitamos agregar dos capacidades de Linux.- CAP_SYS_ADMIN es necesario para que Podman se ejecute como raíz dentro del contenedor para montar los sistemas de archivos necesarios.
- CAP_MKNOD es necesario para que Podman se ejecute como root dentro del contenedor para crear los dispositivos en
/dev
. (Tenga en cuenta que Docker lo permite de forma predeterminada).
- Dispositivos:El
--device /dev/fuse
La bandera debe usar fusibles superpuestos dentro del contenedor. Esta opción le dice a Podman en el host que agregue/dev/fuse
al contenedor para que Podman en contenedores pueda usarlo. - Deshabilitar SELinux:
--security-opt label=disable
La opción le dice al Podman del host que deshabilite la separación de SElinux para el contenedor. SELinux no permite que los procesos en contenedores monten todos los sistemas de archivos necesarios para ejecutarse dentro de un contenedor.
Rootful Podman en Docker sin --privileged
# docker run --cap-add=sys_admin --cap-add mknod --device=/dev/fuse --security-opt seccomp=unconfined --security-opt label=disable quay.io/podman/stable podman run ubi8-minimal echo hello
hello
- Nota Docker no admite la coma separada
--cap-add
comando, así que tuve que agregar sys_admin y mknod por separado - Todavía se necesita
--device /dev/fuse
, ya que el contenedor por defecto es/dev/fuse
- Docker siempre crea volúmenes incorporados como propiedad de root:root, por lo que debemos crear un volumen para montar para Podman en el contenedor para poder usarlo para el almacenamiento.
- Como siempre, necesito deshabilitar la separación de SELinux
- También es necesario deshabilitar
seccomp
, ya que Docker tiene unseccomp
ligeramente más estricto política que Podman. Simplemente podría usar una política de seguridad de Podman usando--seccomp=/usr/share/containers/seccomp.json
# docker run --cap-add=sys_admin --cap-add mknod --device=/dev/fuse --security-opt seccomp=/usr/share/containers/seccomp.json --security-opt label=disable quay.io/podman/stable podman run ubi8-minimal echo hello
hello
Podman desarraigado en Podman arraigado sin privilegios
Ejecutar no -contenedor privilegiado con Podman dentro usando un usuario no root usando el espacio de nombres de usuario.
# podman run --user podman --security-opt label=disable --security-opt unmask=ALL --device /dev/fuse -ti quay.io/podman/stable podman run -ti docker.io/busybox echo hello
hello
- Tenga en cuenta que, a diferencia de rooful dentro de rootful case anterior, no tenemos que agregar las capacidades de seguridad peligrosas sys_admin y mknod
- En este caso, estoy ejecutando con
--user podman
, lo que automáticamente hace que Podman dentro del contenedor se ejecute dentro del espacio de nombres de usuario - Todavía deshabilitando SELinux ya que bloquea el montaje
- Todavía necesito
--device /dev/fuse
para usar fuse-overlayfs dentro del contenedor
Podman-remote en Rootful Podman con un socket de Podman filtrado del host
# podman run -v /run:/run --security-opt label=disable quay.io/podman/stable podman --remote run busybox echo hi
hi
En este caso, estamos filtrando el /run
directorio del host al contenedor. Esto permite que podman --remote
para comunicarse con el socket Podman en el host e iniciar el contenedor en el sistema operativo del host. Esta es a menudo la forma en que las personas ejecutan Docker In Docker, especialmente las compilaciones de Docker. También puede ejecutar las compilaciones de Podman de esta manera y aprovechar las imágenes previamente extraídas del sistema.
Tenga en cuenta, sin embargo, que esto es extremadamente inseguro. Los procesos dentro del contenedor pueden hacerse cargo totalmente de la máquina host.
- Todavía necesita deshabilitar la separación de SELinux porque SELinux bloquearía los procesos del contenedor para que no usen sockets filtrados en
/run
. - El
podman --remote
Se agrega una bandera para decirle a Podman que trabaje en modo remoto. Tenga en cuenta que también puede instalar elpodman-remote
ejecutable en un contenedor y utilícelo.
[ ¿Empezando con los contenedores? Consulta este curso gratuito. Implementación de aplicaciones en contenedores:una descripción técnica general. ]
Podman-remote en Docker con un socket de Podman filtrado del host
# docker run -v /run:/run --security-opt label=disable quay.io/podman/stable podman --remote run busybox echo hi
hi
El mismo ejemplo funciona para un contenedor Docker.
Este ejemplo muestra un contenedor completamente bloqueado (aparte de la desactivación de SELinux) con el socket de Podman filtrado en el contenedor. SELinux bloquearía este acceso, como debería.
# /bin/podman run --security-opt=label=disable -v /run/podman:/run/podman quay.io/podman/stable podman --remote run alpine echo hi
hi
Rootless Podman con contenedor rootful Podman
$ podman run --privileged quay.io/podman/stable podman run ubi8 echo hello
Resolved "ubi8" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
..
hello
Podman sin raíz ejecutando Podman sin raíz
$ podman run --security-opt label=disable --user podman --device /dev/fuse quay.io/podman/stable podman run alpine echo hello
Reflexiones finales
Ahora tiene algo de contexto para Podman en las opciones de Podman, utilizando los modos rootful y rootless. en varias combinaciones. También tiene una mejor idea de los privilegios necesarios y las consideraciones que rodean al --privileged
bandera.
La segunda parte de esta serie analiza el uso de Podman y Kubernetes. El artículo cubre un territorio similar pero dentro del contexto de Kubernetes.
[ ¿Quiere poner a prueba sus habilidades de administrador de sistemas? Tome una evaluación de habilidades hoy. ]