Conteúdo

Rootless Docker e Podman: execute contêineres sem root

As práticas recomendadas de segurança mostram na prática que quem pode usar Docker também pode montar o diretório raiz do host em um contêiner e ler e gravar qualquer arquivo, o que equivale a ter privilégios de root no host. Isso acontece porque o próprio Docker Engine (dockerd) é executado como root, e o root dentro do contêiner é o root do host (embora vários mecanismos de isolamento o restrinjam).

Esta seção apresenta duas maneiras de dispensar o root: o modo Rootless do Docker e outra ferramenta de contêineres, o Podman.

Docker Rootless: o Docker Engine executado como usuário comum

No modo Rootless, o dockerd e todos os contêineres são executados como um usuário comum. Ele usa o user namespace do Linux: dentro do contêiner, o usuário parece ser root (uid 0), mas no host corresponde à sua conta ou a um intervalo de uids sem privilégios.

Esta seção usa a imagem oficial docker:29.9-dind-rootless para os testes, sem afetar as configurações do 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)

Os logs mostram que o Docker Engine está escutando em /run/user/1000/docker.sock (o caminho exclusivo do usuário 1000), e não no /var/run/docker.sock usado normalmente. O usuário que executa o dockerd é rootless (uid 1000), e não root.

Quem é o root dentro do contêiner

Faça o comando docker se conectar ao socket rootless (DOCKER_HOST) e execute um contêiner:

$ 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
  • As opções de segurança de docker info incluem name=rootless.
  • O id dentro do contêiner mostra uid=0(root): para os programas no contêiner, ele é root.
  • Visto do host (camada externa), o mesmo processo sleep 300 pertence ao usuário comum rootless.

Teste: mesmo montando o diretório raiz do host, não é possível ler /etc/shadow

/etc/shadow armazena hashes de senhas e só pode ser lido por root. Monte / do host com o Docker convencional e com o Docker Rootless e tente ler o arquivo:

$ 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 convencional: o root dentro do contêiner leu diretamente o /etc/shadow do host.
  • Docker Rootless: o usuário continua sendo root dentro do contêiner (id -u é 0), mas recebe `Permission denied ao tentar ler o arquivo. No host, ele é apenas um usuário comum, então suas permissões não vão além das da conta que iniciou o Docker.

Assim, mesmo que o contêiner seja invadido ou alguém use -v /:/host por engano, o impacto fica limitado àquela conta de usuário.

Instalar o Docker Rootless no Linux

As etapas abaixo foram compiladas com base na documentação oficial do Docker. Este tutorial não fez uma instalação real no host (a instalação altera as configurações do sistema host); na prática, consulte a documentação oficial.

# 1. Instale os pacotes necessários (Ubuntu / Debian)
sudo apt-get install -y uidmap dbus-user-session

# 2. Se o Docker convencional já estiver instalado, é recomendável desativá-lo primeiro
sudo systemctl disable --now docker.service docker.socket

# 3. Execute o script de instalação como usuário comum (instalado junto com o pacote Docker Engine)
dockerd-rootless-setuptool.sh install

# 4. Configure o comando docker para se conectar ao socket rootless (adicione ao ~/.bashrc)
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock

# 5. Inicie-o na inicialização (ele continuará em execução depois que o usuário sair)
systemctl --user enable docker
sudo loginctl enable-linger $(whoami)

Limitações do modo rootless

LimitaçãoDescrição e solução
Portas abaixo de 1024Por padrão, usuários comuns não podem vincular as portas 80 e 443; -p 80:80 falhará. Use uma porta como 8080 e encaminhe o tráfego por um proxy reverso, ou ajuste a configuração do sistema net.ipv4.ip_unprivileged_port_start
Limites de recursos--memory e --cpus exigem cgroup v2 no host e que o systemd delegue permissões ao usuário
Desempenho da redeO tráfego é encaminhado por componentes de rede no espaço do usuário, então a taxa de transferência é menor que no modo comum
Localização dos dadosImagens e Volumes ficam no diretório pessoal do usuário (~/.local/share/docker) e não são compartilhados com o modo comum
Alguns recursosPor exemplo, configurações do AppArmor e alguns drivers de armazenamento e rede não são compatíveis

O ambiente de teste deste tutorial teve o ip_unprivileged_port_start ajustado, então -p 80:80 não falhou. Não foi possível reproduzir aqui o primeiro ponto da tabela.

Podman: ferramenta de contêineres sem daemon residente

Podman é uma ferramenta de contêineres de código aberto liderada pela Red Hat e é a ferramenta de contêineres padrão em distribuições como Fedora e RHEL. As principais diferenças em relação ao Docker são:

  • Sem daemon residente (daemonless): os comandos do Docker são executados por meio do dockerd; os comandos do Podman criam contêineres diretamente, e o contêiner é um processo filho do seu processo.
  • Rootless por padrão: quando um usuário comum executa podman, ele já está no modo rootless.
  • Comandos quase iguais aos do Docker: opções de run, build, ps, images, exec, logs e outros são iguais.

Teste prático: use o Podman como o Docker

Execute dentro da imagem quay.io/podman/stable (o cgroup v1 da máquina de teste faz o Podman exibir um aviso de descontinuação, então adicione PODMAN_IGNORE_CGROUPSV1_WARNING=1 para ocultá-lo):

$ 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
  • O uso de podman run é igual ao do Docker, e você pode usar diretamente opções como --rm, -d e -p.
  • podman build usa diretamente o Dockerfile do aplicativo Node.js, sem precisar de nenhuma alteração, e a compilação é concluída com sucesso. O contêiner também responde normalmente.
  • Recomendamos escrever o nome completo da imagem, como docker.io/library/alpine:3.23. O nome curto do Podman (alpine:3.23) define de qual Registry baixar de acordo com a configuração do sistema, que pode variar entre distribuições.
  • Por fim, mude para o usuário comum podman para executar: podman info mostra rootless como true; dentro do contêiner, o uid continua sendo 0, mas, assim como no Docker rootless, ele corresponde apenas a um usuário comum no host.

Instalação

# Ubuntu / Debian
sudo apt-get install -y podman

# Fedora / RHEL
sudo dnf install -y podman

No Windows e no macOS, você pode instalar o Podman Desktop, que, assim como o Docker Desktop, executa Linux em uma máquina virtual.

Como escolher entre Docker, Docker rootless e Podman

Docker (comum)Docker rootlessPodman
Daemon residentedockerd (root)dockerd (usuário comum)Nenhum
Permissão efetiva de root dentro do contêinerroot do host (com isolamento)Usuário comumUsuário comum (no modo rootless)
Compatibilidade com os comandos deste tutorialTotalQuase totalEm grande parte
Docker ComposeIntegradoIntegradopodman compose chama uma implementação externa
Ferramentas do ecossistema (Portainer, Traefik etc.)Compatibilidade completaCompatível na maioria dos casosExige configuração adicional do socket
Indicado paraDesenvolvimento geral, Docker Desktop e a maioria dos servidoresServidores compartilhados por vários usuários e requisitos de segurança elevadosAmbientes RHEL / Fedora e quem não quer um daemon residente

Para a maioria dos iniciantes e projetos comuns, basta usar o Docker como neste tutorial. Se o servidor tiver vários usuários ou requisitos de segurança mais rigorosos, considere o Docker rootless ou o Podman.

Resumo

  • No Docker comum, o dockerd é executado como root; quem pode usar o Docker tem, na prática, acesso de root ao host.
  • O modo rootless usa user namespaces para mapear o root dentro do contêiner a um usuário comum no host. No teste prático, não foi possível ler /etc/shadow do host.
  • As principais limitações do modo rootless são as portas abaixo de 1024, os limites de recursos que exigem cgroup v2 e o desempenho da rede.
  • O Podman não tem daemon residente, é rootless por padrão e tem comandos quase iguais aos do Docker; você pode construir imagens diretamente a partir de um Dockerfile.

Exercícios

Exercício 1: no Docker comum, execute docker run --rm alpine:3.23 id e depois docker run --rm -u 1000:1000 alpine:3.23 id. Qual é a diferença em relação ao modo rootless?

Resposta

-u 1000:1000 apenas faz com que o processo dentro do contêiner seja executado com uid 1000; o dockerd continua sendo root, e quem pode usar o Docker ainda pode iniciar outro contêiner como root sem -u. No modo rootless, todo o Docker Engine é executado como um usuário comum, e nenhum contêiner pode obter permissões de root no host. Os dois modos podem ser usados ao mesmo tempo.

Exercício 2: no Docker rootless, a execução de docker run -d -p 80:80 nginx:1.30-alpine falhou. Quais são duas maneiras de resolver isso?

Resposta
  1. Use uma porta acima de 1024, como -p 8080:80, e depois encaminhe a porta 80 para a 8080 usando um proxy reverso no host ou uma regra de firewall.
  2. Ajuste a configuração do sistema para permitir que usuários comuns vinculem a porta 80: sudo sysctl net.ipv4.ip_unprivileged_port_start=80 (adicione a configuração a /etc/sysctl.conf para mantê-la após a reinicialização).

Perguntas frequentes

O modo Rootless é mais lento?

Os programas executados dentro dos contêineres têm velocidade semelhante. A rede (com encaminhamento em espaço de usuário) e algumas operações de sistema de arquivos são um pouco mais lentas que no modo convencional, mas a diferença costuma passar despercebida na maioria dos sites e usos de desenvolvimento.

O Docker Desktop precisa do Rootless?

Não. No Windows e no macOS, o Docker Desktop executa o Docker Engine dentro de uma máquina virtual, separado do seu computador. O Rootless é usado principalmente em servidores e desktops Linux.

Posso substituir diretamente o comando docker por podman?

Na maioria dos casos, sim. As opções de podman run, podman build e podman ps são quase iguais, e muita gente simplesmente define alias docker=podman. As diferenças são a ausência de um daemon permanente, o modo rootless por padrão e a necessidade de configurar separadamente o Compose e as ferramentas relacionadas ao socket do Docker.

O Podman pode usar compose.yaml?

Sim. podman compose chama uma implementação do Compose instalada no sistema (docker-compose ou podman-compose) para processar compose.yaml. A maioria das configurações pode ser usada.

Atualizado 13 de outubro de 2026