Contenido
Tutorial de Docker rootless y Podman: ejecutar contenedores sin root
En Prácticas recomendadas de seguridad comprobamos que cualquiera que pueda usar Docker puede montar el directorio raíz del host en un contenedor y leer y escribir cualquier archivo: es equivalente a tener permisos de root en el host. Esto se debe a que Docker Engine (dockerd) se ejecuta como root, por lo que el root del contenedor es el root del host (aunque esté limitado por varios mecanismos de aislamiento).
En esta sección se presentan dos formas de prescindir de root: el modo Rootless de Docker y otra herramienta de contenedores, Podman.
Docker Rootless: Docker Engine se ejecuta como un usuario normal
El modo Rootless ejecuta dockerd y todos los contenedores como un usuario normal. Utiliza el espacio de nombres de usuario de Linux: dentro del contenedor parece root (uid 0), pero en el host corresponde a tu cuenta o a un intervalo de uid sin privilegios.
En esta sección hacemos una prueba con la imagen oficial docker:29.9-dind-rootless, sin afectar la configuración del host:
$ docker run -d --name rl --privileged docker:29.9-dind-rootless
93e609c8808360d7e63bdc214ab2ff0e76af520fb0fb9dec5b5852d57a4881fe
$ docker logs rl 2>&1 | tail -n 5
time="2026-10-13T05:22:59.775914576Z" level=info msg="Initializing buildkit"
time="2026-10-13T05:22:59.918099929Z" level=info msg="Completed buildkit initialization"
time="2026-10-13T05:22:59.929895038Z" level=info msg="Daemon has completed initialization"
time="2026-10-13T05:22:59.930093633Z" level=info msg="API listen on /run/user/1000/docker.sock"
time="2026-10-13T05:22:59.930231753Z" level=info msg="API listen on [::]:2376"
$ docker exec rl id
uid=1000(rootless) gid=1000(rootless) groups=1000(rootless)
Los registros muestran que Docker Engine escucha en /run/user/1000/docker.sock (una ruta exclusiva del usuario 1000), en lugar de la ruta habitual /var/run/docker.sock. El usuario que ejecuta dockerd es rootless (uid 1000), no root.
Quién es el root dentro del contenedor
Conecta el comando docker al socket de Rootless (DOCKER_HOST) y ejecuta un contenedor:
$ docker exec -e DOCKER_HOST=unix:///run/user/1000/docker.sock rl docker info --format '{{json .SecurityOptions}}'
["name=seccomp,profile=builtin","name=rootless"]
$ docker exec -e DOCKER_HOST=unix:///run/user/1000/docker.sock rl docker run -d --name sleeper alpine:3.23 sleep 300
18986d442e9b9282178d96e7187534b9ac19a83dd42e3b4671a5243b55bcf1ff
$ docker exec -e DOCKER_HOST=unix:///run/user/1000/docker.sock rl docker exec sleeper id
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
$ docker exec rl ps -o user,pid,args | grep 'sleep 300' | grep -v grep
rootless 382 sleep 300
- En las opciones de seguridad de
docker infoaparecename=rootless. iddentro del contenedor muestrauid=0(root), así que para los programas del contenedor ese usuario es root.- Desde el host (el exterior), el propietario del mismo proceso
sleep 300es el usuario normalrootless.
Prueba: montar el directorio raíz del host no permite leer /etc/shadow
/etc/shadow almacena hashes de contraseñas y solo root puede leerlo. Monta / del host e intenta leer el archivo con Docker normal y con Docker Rootless:
$ docker run --rm -v /:/host alpine:3.23 sh -c "id -u; head -n 1 /host/etc/shadow"
0
root:*::0:::::
$ docker exec -e DOCKER_HOST=unix:///run/user/1000/docker.sock rl docker run --rm -v /:/host alpine:3.23 sh -c 'id -u; head -n 1 /host/etc/shadow'
0
head: /host/etc/shadow: Permission denied
- Docker normal: el root del contenedor leyó directamente
/etc/shadowdel host. - Docker Rootless: dentro del contenedor también es root (
id -udevuelve 0), pero al intentar leer el archivo recibePermission denied. En el host solo es un usuario normal, por lo que sus permisos no superan los de la cuenta que inició Docker.
Así que, aunque alguien comprometa el contenedor o use -v /:/host por error, el impacto se limita a esa cuenta de usuario.
Instalar Docker Rootless en Linux
Estos pasos se han recopilado de la documentación oficial de Docker. Este tutorial no lo ha instalado en el host (la instalación modifica la configuración del sistema). Consulta la documentación oficial antes de hacerlo.
# 1. Instala los paquetes necesarios (Ubuntu / Debian)
sudo apt-get install -y uidmap dbus-user-session
# 2. Si ya tienes instalado Docker normal, se recomienda desactivarlo primero
sudo systemctl disable --now docker.service docker.socket
# 3. Ejecuta el script de instalación como usuario normal (se instala con el paquete de Docker Engine)
dockerd-rootless-setuptool.sh install
# 4. Conecta el comando docker al socket rootless (añádelo a ~/.bashrc)
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
# 5. Haz que se inicie al arrancar (seguirá ejecutándose después de cerrar sesión)
systemctl --user enable docker
sudo loginctl enable-linger $(whoami)
Limitaciones de Rootless
| Limitación | Descripción y solución |
|---|---|
| Puertos por debajo de 1024 | Los usuarios normales no pueden enlazar los puertos 80 y 443 de forma predeterminada; -p 80:80 fallará. Usa otro puerto, como 8080, y reenvía el tráfico mediante un proxy inverso, o ajusta la configuración del sistema net.ipv4.ip_unprivileged_port_start |
| Límites de recursos | --memory y --cpus requieren que el host use cgroup v2 y que systemd delegue permisos al usuario |
| Rendimiento de red | El tráfico se reenvía mediante componentes de red en espacio de usuario, por lo que el rendimiento es inferior al del modo normal |
| Ubicación de los datos | Las imágenes y los Volume se guardan en el directorio personal del usuario (~/.local/share/docker) y no se comparten con los datos del modo normal |
| Algunas funciones | Por ejemplo, no se admiten la configuración de AppArmor ni algunos controladores de almacenamiento y red |
El entorno de prueba de este tutorial tiene ajustado
ip_unprivileged_port_start, así que-p 80:80no dio error y no es posible reproducir aquí el primer punto de la tabla.
Podman: una herramienta de contenedores que no necesita un proceso residente
Podman es una herramienta de contenedores de código abierto liderada por Red Hat y la herramienta de contenedores predeterminada en distribuciones como Fedora y RHEL. Su mayor diferencia con Docker es la siguiente:
- No tiene un proceso residente (daemonless): los comandos de Docker se ejecutan a través de dockerd; los de Podman crean contenedores directamente, y cada contenedor es un proceso hijo del proceso que ejecutaste.
- Rootless de forma predeterminada: cuando un usuario normal ejecuta
podman, está usando el modo rootless. - Los comandos son casi iguales a los de Docker: los comandos
run,build,ps,images,exec,logsy sus opciones son iguales.
Prueba práctica: usar Podman como Docker
Ejecuta los comandos en la imagen quay.io/podman/stable (el cgroup v1 del host de prueba hace que Podman muestre una advertencia de obsolescencia, así que añadimos PODMAN_IGNORE_CGROUPSV1_WARNING=1 para ocultarla):
$ docker exec -e PODMAN_IGNORE_CGROUPSV1_WARNING=1 podman podman --version
podman version 5.8.7
$ docker exec -e PODMAN_IGNORE_CGROUPSV1_WARNING=1 podman podman run --rm docker.io/library/alpine:3.23 echo hello from podman
hello from podman
$ docker exec -e PODMAN_IGNORE_CGROUPSV1_WARNING=1 podman podman run --rm alpine:3.23 echo hi
hi
$ docker exec -e PODMAN_IGNORE_CGROUPSV1_WARNING=1 podman podman build -q -t express-app /tmp/express-app
npm notice
npm notice New major version of npm available! 11.19.0 -> 12.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
npm notice To update run: npm install -g npm@12.2.0
npm notice
npm warn using --force Recommended protections disabled.
a5a0b2b95ea756ad73b92ead62ece1770fdb26033c69749933fe03e3988dcb8d
$ docker exec -e PODMAN_IGNORE_CGROUPSV1_WARNING=1 podman podman run -d --name app -p 3000:3000 express-app
74aeae727d68aacae32aee45d0705881fbea9b449ac1a5ee07c365b1490f42b3
$ docker exec -e PODMAN_IGNORE_CGROUPSV1_WARNING=1 podman podman exec app wget -qO- localhost:3000
{"message":"Hello from Express","node":"v24.21.0"}
$ docker exec -e PODMAN_IGNORE_CGROUPSV1_WARNING=1 podman su podman -c 'podman run --rm docker.io/library/alpine:3.23 id -u; podman info --format {{.Host.Security.Rootless}}'
0
true
podman runse usa igual que Docker; puedes usar directamente opciones como--rm,-dy-p.podman buildusa directamente el Dockerfile de la aplicación Node.js; la imagen se construye sin cambios y el contenedor responde correctamente.- Conviene escribir el nombre completo de la imagen, por ejemplo,
docker.io/library/alpine:3.23. Podman determina desde qué Registry descargar los nombres cortos (alpine:3.23) según la configuración del sistema, que puede variar entre distribuciones. - Por último, cambia al usuario normal
podmanpara ejecutar los comandos:podman infomuestrarootlesscomotrue. Dentro del contenedor sigue siendo uid 0, pero, al igual que en Rootless Docker, solo corresponde a un usuario normal del host.
Instalación
# Ubuntu / Debian
sudo apt-get install -y podman
# Fedora / RHEL
sudo dnf install -y podman
En Windows y macOS puedes instalar Podman Desktop, que ejecuta Linux en una máquina virtual igual que Docker Desktop.
Cómo elegir entre Docker, Rootless Docker y Podman
| Docker (normal) | Rootless Docker | Podman | |
|---|---|---|---|
| Proceso residente | dockerd (root) | dockerd (usuario normal) | Ninguno |
| Permisos reales de root dentro del contenedor | root del host (con aislamiento) | Usuario normal | Usuario normal (en modo rootless) |
| Compatibilidad con los comandos de este tutorial | Total | Casi total | En su mayoría |
| Docker Compose | Integrado | Integrado | podman compose invoca una implementación externa |
| Herramientas del ecosistema (Portainer, Traefik, etc.) | Compatibilidad completa | Compatibilidad en la mayoría de los casos | Requiere configurar un socket adicional |
| Adecuado para | Desarrollo general, Docker Desktop y la mayoría de los servidores | Servidores compartidos por varios usuarios y requisitos de seguridad altos | Entornos RHEL / Fedora y quienes no quieren un proceso residente |
Para la mayoría de principiantes y proyectos generales, basta con usar Docker como se explica en este tutorial. Si varias personas inician sesión en el servidor o los requisitos de seguridad son altos, considera Rootless Docker o Podman.
Resumen
- El dockerd de Docker en modo normal se ejecuta como root; tener acceso a Docker equivale a tener acceso root al host.
- El modo Rootless usa un user namespace para que root dentro del contenedor corresponda a un usuario normal del host. En la prueba, no fue posible leer
/etc/shadowdel host. - Las principales limitaciones de Rootless son los puertos por debajo de 1024, la necesidad de cgroup v2 para los límites de recursos y el rendimiento de red.
- Podman no tiene un proceso residente, es rootless de forma predeterminada y sus comandos son casi iguales a los de Docker; puedes construir directamente un Dockerfile.
Ejercicios
Ejercicio 1: Ejecuta docker run --rm alpine:3.23 id en Docker normal y luego ejecuta docker run --rm -u 1000:1000 alpine:3.23 id. ¿En qué se diferencia esto del modo Rootless?
Respuesta
-u 1000:1000 solo hace que el proceso dentro del contenedor se ejecute con uid 1000. dockerd sigue siendo root, y quien tenga acceso a Docker puede iniciar otro contenedor como root sin añadir -u. En el modo Rootless, todo Docker Engine se ejecuta como un usuario normal y ningún contenedor puede obtener permisos root en el host. Ambos modos pueden usarse a la vez.
Ejercicio 2: En Rootless Docker, falla docker run -d -p 80:80 nginx:1.30-alpine. ¿Qué dos opciones tienes para resolverlo?
Respuesta
- Usa un puerto superior a 1024, por ejemplo,
-p 8080:80, y luego redirige el puerto 80 al 8080 mediante un proxy inverso en el host o una regla del firewall. - Ajusta la configuración del sistema para permitir que los usuarios normales enlacen el puerto 80:
sudo sysctl net.ipv4.ip_unprivileged_port_start=80(escribe el valor en/etc/sysctl.confpara conservarlo después de reiniciar).
Preguntas frecuentes
¿El modo Rootless es más lento?
Los programas dentro de los contenedores se ejecutan a una velocidad similar. La red (que usa reenvío en el espacio de usuario) y algunas operaciones del sistema de archivos son algo más lentas que en el modo normal. En la mayoría de sitios web y tareas de desarrollo apenas se nota.
¿Docker Desktop necesita Rootless?
No. En Windows y macOS, Docker Desktop ejecuta Docker Engine dentro de una máquina virtual, aislándolo de tu equipo. Rootless se usa principalmente en servidores y escritorios Linux.
¿Puedo sustituir directamente el comando docker por podman?
En la mayoría de los casos, sí. Las opciones de podman run, podman build y podman ps son casi iguales, y mucha gente configura directamente alias docker=podman. Las diferencias son que no hay un daemon permanente, rootless está habilitado de forma predeterminada y las herramientas relacionadas con Compose y el socket de Docker requieren configuración adicional.
¿Podman puede usar compose.yaml?
Sí. podman compose llama a la implementación de Compose instalada en el sistema (docker-compose o podman-compose) para procesar compose.yaml. La mayoría de las configuraciones funcionan.
Actualizado 13 de octubre de 2026