Umbrel
EN

Docker Sandbox Kit: Como isolar agentes de IA com segurança

Descubra como o Docker Sandbox Kit protege seu sistema contra riscos de agentes de IA autônomos e elimine as vulnerabilidades do docker.sock de vez.

Áudio Narrado Ouça este artigo
00:00 / 00:00

Se você entrega o socket do Docker para um agente autônomo de programação, você está dando acesso root à sua máquina para um gerador probabilístico de texto.

Ferramentas como OpenHands, Aider e interfaces locais para o Claude Code quebram um galho enorme no dia a dia. O problema é que a documentação de quase todas sugere fazer o bind mount de /var/run/docker.sock para que o agente consiga criar imagens, rodar testes e gerenciar dependências de apoio. No segundo em que o modelo alucinar um comando, rodar código duvidoso de um repositório clonado ou cair em um prompt injection escondido em um arquivo README, esse acesso ao socket permite que ele escape do container e assuma o controle do seu sistema operacional.

A proposta da Docker de doar a especificação Sandbox Kit para a CNCF (Cloud Native Computing Foundation) mira diretamente nessa falha estrutural. Ao estender a camada de runtime da OCI (Open Container Initiative), a iniciativa busca padronizar ambientes de execução isolados com permissões granulares — aposentando o hábito arriscado de expor o daemon do host para fluxos autônomos.

Veja o que o Sandbox Kit da CNCF muda na prática, por que os métodos atuais de isolamento quebram e como proteger seus ambientes de agentes no Docker agora mesmo usando recursos nativos.


O atalho perigoso: por que o /var/run/docker.sock quebra a segurança

Agentes inteligentes precisam escrever código, instalar dependências, compilar binários e rodar testes de integração. Quando esses testes exigem um banco relacional ou uma instância de cache, o caminho mais rápido para quem desenvolve a ferramenta é repassar o socket do Docker do host para dentro do container do agente.

Esse atalho anula a principal barreira de segurança da máquina. No Linux, ter acesso a /var/run/docker.sock é o mesmo que ter privilégios de root irrestritos no sistema. O daemon do Docker roda como root. Qualquer processo que consiga trocar mensagens com esse socket UNIX pode disparar chamadas diretas de API para criar novos containers, montar qualquer pasta da máquina hospedeira e executar comandos com privilégios de kernel.

bash

O que um agente autônomo com acesso ao socket pode fazer com um único comando:

docker run --rm -v /:/host alpine rm -rf /host/etc

O agente nem precisa ter o binário do cliente docker instalado. Um script em Python ou um comando curl dentro do container conversa direto com o socket UNIX exposto:

# Escapando do container via chamada HTTP pura no socket do Docker
curl --unix-socket /var/run/docker.sock \
  -H "Content-Type: application/json" \
  -d '{"Image": "alpine", "Cmd": ["chroot", "/host", "useradd", "-m", "-G", "sudo", "backdoor"], "Binds": ["/:/host"]}' \
  http://localhost/v1.43/containers/create

Existem três cenários críticos de falha quando você roda agentes com acesso ao daemon:

1. Escalada por Prompt Injection

Se o agente analisa um repositório Git de terceiros contendo uma mensagem de commit maliciosa, uma docstring adulterada ou uma issue envenenada, um prompt injection indireto pode instruir o modelo a tentar escapar do container. Com o socket montado, essa fuga é direta. A LLM assume que está apenas rodando uma rotina de testes para corrigir uma falha, mas na verdade está executando uma instrução que monta o disco do host em um container irmão.

2. Varredura de rede local privada (RFC 1918)

As redes do Docker operam por padrão em modo bridge com saída irrestrita. Um agente desgovernado ou manipulado consegue vasculhar as faixas de IP da sua rede interna (192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12). Ele pode alcançar compartilhamentos SMB abertos no seu NAS, interfaces web de roteadores e dashboards de homelab configurados sem autenticação mútua (mTLS). Se a sua rede local confia no tráfego interno, o agente transforma essa confiança em vetor de invasão.

3. Esgotamento de recursos da máquina host

Modelos de linguagem cometem erros com frequência. Loops infinitos, scripts de compilação sem travamento ou fork bombs acidentais vão devorar descritores de arquivos, memória RAM e ciclos de CPU se não houver limites estritos no nível do cgroups do kernel. Sem travas claras de processo e memória, um agente tentando rodar uma suite de testes pode congelar o host por completo.


O que a especificação Sandbox Kit da CNCF traz de novo

A especificação do Docker Sandbox Kit proposta à CNCF preenche o espaço vazio que existe entre máquinas virtuais tradicionais e containers simples.

Até então, quem precisava de execução segura para agentes ficava entre duas escolhas ruins: rodar máquinas virtuais aninhadas completas (como Firecracker ou QEMU), que consomem gigabytes de memória e demoram segundos para iniciar, ou apelar para o Docker-in-Docker (dind), que exige a perigosa flag --privileged e compartilha camadas demais com o host.

Padrão arriscado tradicional:
[ Container do Agente ] --(bind mount)--> [ /var/run/docker.sock ] --> Controle total do host

Padrão Sandbox CNCF:
[ Container do Agente ] --> [ OCI Sandbox Controller ] --> [ Execução efêmera ]
                                 |- Nega acesso ao disco host   |- Remove privilégios
                                 |- Nega API do daemon          |- Destrói ao encerrar

A especificação de sandbox da OCI detalha como os runtimes de container devem provisionar microambientes efêmeros sem dar acesso ao daemon de controle. Em vez de entregar a engine do Docker para o agente, o Sandbox Kit padroniza:

  • Concessão granular de capacidades: Os agentes pedem ações operacionais pontuais (compilar código, disparar um processo filho, ouvir em uma porta local) em vez de receberem controle irrestrito do daemon.
  • Ciclos de vida declarativos e efêmeros: Os ambientes sobem sob demanda para comandos isolados ou baterias de testes curtas e somem na sequência, sem deixar resíduos nos volumes ou no storage driver da máquina.
  • Flexibilidade de runtime: Pouco importa se o backend roda em cima de namespaces de usuário do Linux ou hypervisors leves para microVMs (como gVisor ou Kata Containers); o agente conversa sempre com uma interface única de baixo privilégio.
  • Planos de controle isolados: O daemon de orquestração fica isolado atrás de uma camada de autorização. O agente não enxerga outros containers ativos, placas de rede locais ou pools de armazenamento do sistema.

Comparativo de estratégias de isolamento

Enquanto a especificação do Sandbox Kit ainda avança na CNCF, quem mantém servidores ou homelabs precisa escolher uma abordagem baseada no risco aceitável e no hardware disponível.

Estratégia Risco de Exposição do Host RAM Base por Agente Tempo de Inicialização Complexidade
Montar docker.sock Crítico (Root completo no host) ~50 MB Instantâneo Trivial
Docker-in-Docker (dind) Alto (Exige --privileged) ~400 MB 3 a 8 segundos Moderada
Podman / Docker Rootless Baixo (Barreira de namespaces do kernel) ~100 MB 1 a 2 segundos Moderada
Compose Endurecido (Recomendado) Muito Baixo (Perfil OCI restrito) ~128 MB Instantâneo Baixa
CNCF Sandbox Kit (Em breve) Mínimo (API granular de permissões) Dinâmica Sub-segundo Nativa

Avaliando os prós e contras

  • Montar docker.sock: Não consome recursos adicionais, mas a segurança é inexistente. Nunca rode código autônomo gerado por LLMs com essa configuração.
  • Docker-in-Docker (dind): Cria um daemon secundário dentro do container e isola o daemon principal. Só que fazer o driver de storage overlay e o cgroups funcionarem internamente costuma exigir o parâmetro --privileged, que desativa filtros seccomp, AppArmor e as travas de capacidades do kernel.
  • Podman / Docker Rootless: Usa namespaces de usuário (userns) para que o root do container seja mapeado para um usuário sem privilégios no sistema real. Evita que o host seja comprometido, mas exige configurações manuais de subuid/subgid e permissões de volume.
  • Compose Endurecido: Usa recursos que já estão instalados no seu Docker. Ao derrubar todas as capacidades do Linux, travar o sistema de arquivos como somente leitura, limitar uso de RAM/CPU e isolar a rede, você garante defesa em profundidade eficiente sem precisar mexer em hypervisors complexos.

Como isolar agentes de IA no Docker hoje mesmo

Não é preciso esperar os padrões upstream chegarem nas distribuições Linux estáveis para ter segurança. Você consegue um isolamento forte hoje configurando um arquivo de Docker Compose com as diretivas certas.

O exemplo a seguir aproveita os mecanismos nativos do Kernel Linux 5.15+: cgroups v2, seccomp, descarte de capabilities e uma rede bridge interna sem rota para a sua rede local.

Salve a configuração abaixo como compose.agent-sandbox.yaml:

services:
  agent-runner:
    image: python:3.11-slim
    container_name: agent_sandbox
    restart: "no"
    
    # Executa com usuário comum sem privilégios (UID 1000)
    user: "1000:1000"

    # Bloqueia escalada de privilégios (ignora binários setuid como sudo/su)
    security_opt:
      - no-new-privileges:true

    # Remove todas as permissões especiais do kernel Linux
    cap_drop:
      - ALL

    # Trava o sistema de arquivos base do container em modo somente leitura
    read_only: true

    # Cria diretórios temporários descartáveis alocados apenas na RAM do host
    # As flags noexec, nosuid e nodev impedem a execução de binários nessas pastas
    tmpfs:
      - /tmp:size=1G,noexec,nosuid,nodev,uid=1000,gid=1000
      - /run:size=64M,noexec,nosuid,nodev,uid=1000,gid=1000

    # Evita fork bombs e limita o uso de hardware do host
    pids_limit: 100
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 2048M
        reservations:
          memory: 128M

    # Redireciona caches de pacotes para a memória RAM (tmpfs) para viabilizar o modo read_only
    environment:
      - HOME=/workspace
      - TMPDIR=/tmp
      - PIP_CACHE_DIR=/tmp/.cache/pip
      - npm_config_cache=/tmp/.npm

    # Monta apenas a pasta de trabalho do projeto
    volumes:
      - type: bind
        source: ./workspace
        target: /workspace
        read_only: false

    working_dir: /workspace

    # Rede fechada: corta rotas de saída e bloqueia acesso à sua rede interna
    networks:
      agent_sandbox_net:
        aliases:
          - sandbox

networks:
  agent_sandbox_net:
    driver: bridge
    internal: true # Bloqueia roteamento externo e varredura da LAN

Por que essa configuração funciona

  • cap_drop: [ ALL ]: Remove todas as permissões de superusuário do kernel. Se o código do agente encontrar uma falha local, ele não terá permissão para alterar rotas de rede, mexer no relógio do sistema, subir módulos de kernel ou inspecionar outros processos via ptrace.
  • security_opt: [ "no-new-privileges:true" ]: Impede que qualquer subprocesso obtenha privilégios adicionais por meio de binários com bits setuid ou setgid. Se alguém injetar um executável malicioso com flag de suid dentro de /workspace, ele não surtirá efeito.
  • read_only: true: Congela a raiz do container. O agente não consegue instalar backdoors persistentes nas pastas do sistema operacional, alterar o /etc/resolv.conf ou corromper binários nativos do container.
  • tmpfs: Ferramentas como pip e npm precisam descompactar arquivos e gerar arquivos de lock temporários. Ao montar um tmpfs em /tmp, o agente ganha uma área de trabalho temporária restrita à RAM, limitada a 1 GB e limpa na hora em que o container para.
  • pids_limit: 100: Coloca um limite rígido na quantidade de processos simultâneos. Se a LLM alucinar e gerar um loop recursivo descontrolado ou uma fork bomb, o kernel encerra as threads excedentes em vez de travar a máquina hospedeira.
  • internal: true: Essa diretiva isola a interface de rede bridge. O container fica completamente impedido de falar com roteadores, outros dispositivos na sua rede interna ou servidores na internet.

Testando o isolamento do agente

Para validar o ambiente de sandbox, crie uma pasta local para a área de trabalho e inicie o container:

# Cria o diretório de trabalho com permissão para o UID 1000
mkdir -p workspace
chown -R 1000:1000 workspace

# Executa um comando de teste dentro da sandbox
docker compose -f compose.agent-sandbox.yaml run --rm agent-runner python3 -c "
import os
print(f'User UID: {os.getuid()}')
print(f'Filesystem writable: {os.access(\"/etc\", os.W_OK)}')
print(f'Workspace writable: {os.access(\"/workspace\", os.W_OK)}')
"

A saída precisa confirmar que o processo roda com UID 1000, que a pasta /etc está bloqueada para escrita e que apenas /workspace aceita alterações:

User UID: 1000
Filesystem writable: False
Workspace writable: True

Problemas comuns ao isolar agentes (e como contornar)

Fique atento a estes problemas práticos antes de subir agentes em containers restritos:

1. Falha com gerenciadores de pacotes em modo somente leitura

Definir read_only: true quebra comandos como npm install, pip install ou cargo build logo de cara, porque esses utilitários tentam gravar diretórios de cache em /root/.cache, /home/node ou /workspace/.cache.

Ajuste isso apontando as variáveis de ambiente dos diretórios de cache para a pasta temporária em /tmp:

environment:
  - PIP_CACHE_DIR=/tmp/.cache/pip
  - npm_config_cache=/tmp/.npm
  - CARGO_HOME=/tmp/.cargo
  - GOCACHE=/tmp/.go-cache

Caso os scripts de build precisem rodar binários gerados durante o processo dentro de /tmp, remova o parâmetro noexec da linha do /tmp no Compose:

tmpfs:
  - /tmp:size=1G,nosuid,nodev,uid=1000,gid=1000

2. Achar que redes bridge padrão do Docker são isoladas

Por padrão, uma rede comum de container alcança o endereço de IP do host e qualquer equipamento na sua rede local física (endereços RFC 1918). Se você esquecer o parâmetro internal: true, o container conseguirá se comunicar com seu roteador, outros containers de homelab e servidores internos. Use sempre internal: true ou defina regras estritas via nftables/iptables na interface da bridge.

Se o seu fluxo de desenvolvimento realmente precisa de internet para puxar bibliotecas externas, passe o tráfego por um forward proxy explícito (como Squid ou Tinyproxy) configurado com uma lista de domínios permitidos restrita aos repositórios oficiais (pypi.org, npmjs.org):

[ Agente protegido ] ---> [ Forward Proxy (Lista permitida) ] ---> [ PyPI / npm ]
         |
         x (Bloqueado: 192.168.1.0/24 e 10.0.0.0/8)

3. Habilitar capacidades cegas para debuggers

Quando agentes tentam utilizar utilitários como o gdb ou profiladores de memória, eles costumam pedir a permissão SYS_PTRACE. Conceder SYS_PTRACE enfraquece o isolamento de processos dentro de namespaces compartilhados. Se a sua rotina exige inspeção profunda de chamadas de sistema, rode o agente em uma microVM de verdade (como Firecracker) em vez de enfraquecer seus perfis seccomp no Docker.

4. Conflitos de permissão de arquivo e mapeamento de UID/GID

Se os arquivos do seu projeto no host pertencem ao UID 501 (padrão no macOS) ou UID 1000 (comum no Linux monousuário), mas o container roda com um usuário diferente, o agente vai falhar com erros de "permission denied" sempre que tentar salvar um arquivo editado. Garanta que a diretiva user: no Compose bata com o seu usuário local:

# Descubra seu UID e GID atuais
id -u
id -g

# Passe os identificadores na inicialização do container
UID_GID="$(id -u):$(id -g)" docker compose -f compose.agent-sandbox.yaml run --user "$UID_GID" --rm agent-runner bash

Perguntas frequentes (FAQ)

O que é a especificação Sandbox Kit doada à CNCF?

É uma especificação aberta pensada para padronizar como engines de containers constroem, operam e isolam ambientes descartáveis de execução. Ela entrega para agentes de IA e ferramentas de automação uma interface comum e de menor privilégio, eliminando a dependência do socket do daemon Docker do host.

Como executar código de LLM e agentes com segurança no Docker?

Rode o container sem nenhum bind mount de /var/run/docker.sock. Configure um usuário comum sem privilégios de root, descarte todas as capacidades do kernel usando cap_drop: [ALL], trave o sistema de arquivos como somente leitura (read_only: true), isole o container em uma rede bridge com internal: true e defina limites restritos de memória, CPU e contagem de processos via cgroups v2.

Por que montar o /var/run/docker.sock em agentes inteligentes é perigoso?

O socket do Docker é uma API de controle direto e irrestrito para o daemon no host, que executa como root. Qualquer processo que envie comandos para ele tem o mesmo poder do administrador da máquina. Um agente que receba instruções maliciosas por prompt injection pode usar essa porta para montar o disco rígido do host dentro de outro container, ler arquivos protegidos ou criar contas com acesso permanente ao sistema.

Qual a diferença entre o Sandbox Kit da CNCF e o Docker-in-Docker (dind)?

O Docker-in-Docker tradicional depende de containers filhos rodando com o argumento --privileged e permissões amplas de kernel, abrindo brechas consideráveis na máquina física. O Sandbox Kit da CNCF trabalha direto na camada da OCI para instanciar microambientes enxutos e isolados, impondo limites operacionais sem precisar de daemons privilegiados rodando dentro de outros containers.


Leia também no cluster

  • /en/posts/cursor-xai-vs-local-llms-privacy-guide-for-homelabs/
  • /en/posts/docker-sandbox-kit-spec-v3-hardening-ai-agent-containers/
  • /en/posts/docker-sandboxes-secure-isolation-for-autonomous-ai-agents/

Aplique as regras de isolamento no seu Compose antes de dar permissão para qualquer script de LLM rodar localmente. Teste primeiro a escrita nas pastas permitidas, confira se o acesso à rede interna está bloqueado e monitore o comportamento dos processos. É bem mais tranquilo perder dez minutos ajustando permissões do que passar a tarde restaurando arquivos do sistema operacional.

Relacionados neste cluster

  • /pt/posts/como-isolar-agentes-ia-docker-sandbox/
  • /pt/posts/como-isolar-agentes-ia-docker/
  • /pt/posts/como-isolar-containers-docker-seguranca/