← Blog

Segurança de runtime de containers: protegendo containers em execução

Guia de segurança de runtime de containers: primitivas de isolamento, flags de hardening, vetores de escape e detecção para containers em produção.

Bruno Baldo·5 de out. de 2026·Atualizado em 14 de set. de 2026·11 min de leitura·Revisado por Rainforest Technologies

A segurança de runtime de containers é a prática de proteger os containers enquanto eles estão de fato em execução, e não enquanto estão sendo construídos ou armazenados. Ela importa porque um container que saiu de uma imagem limpa e totalmente escaneada não fica seguro para sempre. No momento em que passa a servir tráfego, ele se torna um alvo ao vivo: suas dependências em execução podem ser atingidas por um zero-day recém-divulgado, seu filesystem pode sofrer drift à medida que um atacante escreve novos binários, e qualquer fraqueza no isolamento do host pode ser transformada em uma rota de saída do container. Este guia é um mergulho profundo na proteção de containers em runtime — as primitivas de isolamento que confinam um container, as flags de hardening do runtime do Docker que as apertam, os vetores de container escape que você precisa fechar, e a detecção e resposta que capturam o que escapa.

Este artigo faz parte do nosso cluster de Docker container security. Se você ainda não endureceu a própria imagem, combine-o com o nosso guia de Dockerfile security best practices, e se você roda em Kubernetes, leia-o junto com Kubernetes pod security.

Por que a segurança de runtime importa

É tentador pensar que a segurança termina quando uma imagem escaneada passa pelo pipeline. Não termina. Um scan em tempo de build é um instantâneo de um momento que já está no passado quando o container entra em operação.

Três coisas mudam quando um container está em execução. Primeiro, novas vulnerabilidades são divulgadas o tempo todo. A biblioteca que estava limpa quando você construiu a imagem no mês passado pode ter uma CVE crítica anunciada hoje, e o container em execução fica exposto até ser reconstruído e reimplantado. Segundo, os containers sofrem drift. Um atacante que consegue execução de código dentro de um container pode instalar ferramentas, escrever payloads, abrir shells e abrir conexões de rede — nada disso existia na imagem original. A lacuna entre o que você entregou e o que agora está em execução é exatamente onde mora uma intrusão. Terceiro, o isolamento entre container e host é apenas tão forte quanto sua configuração. Um container não é uma máquina virtual; ele compartilha o kernel do host, e uma única flag ampla demais pode derrubar por completo a fronteira.

A segurança de runtime é a camada que assume que o comprometimento eventualmente vai acontecer e trabalha para mantê-lo contido e visível.

As primitivas de isolamento — e como apertá-las

Os containers são isolados por recursos do kernel do Linux, não por um hypervisor. Entender essas primitivas é o jogo inteiro, porque endurecer um container significa apertar cada uma delas além do seu padrão.

Os namespaces dão a um container sua própria visão do sistema — sua própria árvore de processos, stack de rede, tabela de montagem e IDs de usuário. São eles que fazem um container parecer uma máquina separada. O padrão costuma ser sólido, mas não o enfraqueça: compartilhar o PID, a rede ou o namespace de IPC do host com o container reintroduz exatamente a visibilidade que os namespaces existem para remover.

Os cgroups (control groups) limitam quanta CPU, memória e I/O um container pode consumir. Isso é um controle de segurança, não apenas de operações: um container sem limites pode esgotar um host e deixar todos os vizinhos sem recursos, o que é uma condição de negação de serviço, chegue ela por bug ou por má-fé. Defina limites explícitos:

docker run --memory=256m --cpus=0.5 --pids-limit=100 myapp:1.4.2

As capabilities do Linux fatiam o poder do root em privilégios discretos. Por padrão, o Docker concede a um container um conjunto moderado, mas a maioria das aplicações não precisa de quase nenhum deles. A postura correta é remover tudo e adicionar de volta apenas o que for genuinamente necessário:

docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp:1.4.2

E nunca recorra a --privileged, que desativa a maioria dessas proteções de uma só vez (mais sobre isso abaixo).

O seccomp filtra as chamadas de sistema que um container pode fazer. O Docker vem com um profile de seccomp padrão que já bloqueia dezenas de syscalls perigosas; o erro é executar com --security-opt seccomp=unconfined, que desliga esse filtro. Mantenha o padrão, ou forneça um profile personalizado mais restritivo para cargas de trabalho sensíveis.

O AppArmor e o SELinux são sistemas de controle de acesso mandatório que restringem quais arquivos e recursos um processo pode tocar, independentemente das permissões Unix. O Docker aplica um profile de AppArmor padrão quando disponível; em hosts com SELinux, labels impõem uma fronteira semelhante. Deixe-os habilitados e escreva um profile personalizado quando uma carga de trabalho justificar.

Mais duas flags pertencem a todo docker run endurecido:

docker run \

  --read-only \

  --tmpfs /tmp \

  --security-opt no-new-privileges \

  --cap-drop=ALL \

  myapp:1.4.2

O `--read-only` torna o filesystem raiz do container imutável, de modo que um atacante não consiga soltar um payload nem sobrescrever um binário; monte um `--tmpfs` para os poucos caminhos que genuinamente precisam ser graváveis. O `--security-opt no-new-privileges` impede que um processo ganhe mais privilégios do que o seu pai — por exemplo, por meio de um binário setuid —, o que fecha um passo comum de escalonamento.

O socket do Docker é um risco de runtime

Uma configuração incorreta merece sua própria seção porque é ao mesmo tempo comum e catastrófica: montar o socket do Docker.

O daemon do Docker escuta em /var/run/docker.sock, e qualquer coisa capaz de falar com esse socket pode controlar o daemon — o que significa que pode iniciar um novo container, montar o filesystem raiz do host dentro dele e executar como root no host. Montar o socket dentro de um container (-v /var/run/docker.sock:/var/run/docker.sock) equivale, portanto, a conceder a esse container o controle total do host e de todos os outros containers nele.

CI runners, agentes de monitoramento e ferramentas de dashboard costumam pedir o socket por conveniência. Trate cada pedido desse tipo como um risco de tomada do host. Prefira um socket proxy que exponha apenas as chamadas de API específicas e somente leitura de que uma ferramenta realmente precisa, execute a carga de trabalho de forma rootless, ou use uma abordagem de tooling sem daemon. Se um container realmente precisa gerenciar containers, isole-o e nunca exponha essa capacidade a qualquer coisa que lide com entrada não confiável.

Runtime rootless e user namespaces

Por padrão, o daemon do Docker roda como root, e um processo que escapa de um container muitas vezes cai com poder equivalente a root no host. Dois mecanismos reduzem esse raio de impacto.

Os user namespaces remapeiam o root do container (UID 0) para um UID sem privilégios no host. Mesmo que um processo acredite ser root dentro do container, para o kernel do host ele é um usuário nobody sem privilégios significativos — de modo que um escape rende muito menos. Habilite isso com a configuração userns-remap do daemon.

O rootless mode vai além e executa todo o runtime do container como um usuário não-root, de modo que o próprio daemon nunca detém root. Ele fecha a classe de ataques que miram diretamente o daemon privilegiado. O rootless mode tem algumas concessões de funcionalidade, mas para muitas cargas de trabalho é o passo de hardening de runtime de maior alavancagem disponível.

Vetores de container escape e suas mitigações

Um container escape ocorre quando um processo rompe seu isolamento e ganha acesso ao host ou a outros containers. Quase todo escape do mundo real vem de uma de poucas origens:

  • Containers privilegiados. O --privileged concede quase todas as capabilities, desativa o confinamento por seccomp e AppArmor e expõe os dispositivos do host. A partir de um container privilegiado, escapar para o host costuma ser trivial. Mitigação: nunca execute privilegiado; remova capabilities e adicione de volta o mínimo.
  • Montagens do host. Fazer bind mount de um caminho sensível do host — /, /etc, /var/run ou um nó de dispositivo — permite que um container comprometido leia ou altere o host diretamente. Mitigação: monte apenas o necessário, em somente leitura sempre que possível, e nunca monte o filesystem raiz nem o socket do Docker em cargas de trabalho não confiáveis.
  • O socket do Docker exposto. Abordado acima — uma rota direta para o root do host. Mitigação: mantenha o socket fora dos containers, ou coloque-o atrás de um proxy restritivo.
  • Exploits de kernel. Como todo container compartilha o kernel do host, uma vulnerabilidade de nível de kernel pode ser explorada de dentro de um container para romper a fronteira. Mitigação: aplique patches no kernel do host prontamente, mantenha o seccomp habilitado para reduzir a superfície de syscall alcançável, e considere um runtime em sandbox que adicione uma camada entre container e kernel para cargas de trabalho de alto risco.

O padrão nos quatro casos é o mesmo: o escape só é possível porque um padrão foi afrouxado. O hardening de runtime é, em grande parte, a disciplina de não afrouxá-los.

Detecção e resposta em runtime

O hardening reduz as chances de um ataque bem-sucedido; não as elimina, e não lhe diz nada quando um está em andamento. Esse é o trabalho da detecção em runtime.

O monitoramento comportamental e de syscall observa o que um container realmente faz em relação a um modelo do que ele deveria fazer. Um servidor web que de repente abre um shell, dispara um gerenciador de pacotes ou executa um compilador está se comportando de forma anormal, e um monitor em nível de syscall pode sinalizar ou bloquear isso em tempo real. Este é o modelo popularizado por ferramentas open-source de monitoramento de syscall: defina regras para comportamento suspeito — uma conexão de saída inesperada, uma escrita em um caminho sensível, uma tentativa de escalonamento de privilégios — e alerte no instante em que uma delas dispara.

A detecção de anomalias constrói uma linha de base da atividade normal de processos, arquivos e rede para cada carga de trabalho e expõe os desvios em relação a ela, o que é útil para pegar os ataques que nenhuma regra explícita antecipou.

A detecção de drift compara o container em execução com a imagem a partir da qual ele foi construído. Como um container bem construído deve ser imutável em runtime, qualquer novo binário, arquivo modificado ou processo inesperado é um forte sinal de que algo mudou que não deveria ter mudado — e a detecção de drift transforma esse princípio em um alerta.

Nada disso é útil sem logging. Envie os logs do container e do host — execução de processos, conexões de rede, mudanças em arquivos e eventos do daemon — para um armazenamento central que os próprios containers não consigam alcançar, de modo que um atacante que comprometa um container não possa apagar seus rastros. Quando um incidente acontece, essa trilha de logs é a diferença entre uma investigação limpa e um chute. Construa um plano de resposta a incidentes em torno dela: como você isola um container suspeito, preserva seu estado para forense e rotaciona quaisquer credenciais que ele possa ter tocado, antes de encerrá-lo.

A ligação com o runtime do Kubernetes

Tudo aqui se aplica igualmente quando um container roda dentro de um pod do Kubernetes — as primitivas são as mesmas, só a interface muda. As flags do docker run neste artigo mapeiam para campos no securityContext de um pod: remover capabilities, executar como não-root, um filesystem raiz somente leitura, allowPrivilegeEscalation: false e um profile de seccomp. Se você opera em Kubernetes, leia isto junto com o nosso guia de Kubernetes pod security, que cobre como a plataforma impõe essas mesmas proteções de runtime em um cluster.

Como a Rainforest ajuda

A Rainforest traz a segurança relevante para o runtime para dentro do fluxo de trabalho do desenvolvedor, em vez de acoplá-la depois da implantação. Nosso scanning de container security inspeciona suas imagens e sua configuração em busca exatamente dos problemas que este artigo aborda — flags privilegiadas, ausência de remoção de capabilities, um socket do Docker exposto, limites de recursos ausentes, execução como root e dependências que carregam vulnerabilidades conhecidas — e os expõe no pull request, antes de o container sequer rodar. Como novas vulnerabilidades são divulgadas depois de uma imagem ser entregue, esse scanning é contínuo: uma dependência que se torne vulnerável na semana que vem é sinalizada contra imagens que já estão no seu registry, para que você saiba o que reconstruir.

O resultado é uma imagem consistente ao longo do ciclo de vida: o mesmo hardening que você impõe em runtime é verificado como código, de modo que uma configuração incorreta é pega enquanto ainda é uma pequena mudança e ainda não um incidente ao vivo. Ele é uma parte da nossa plataforma mais ampla de application security testing.

Se você quer ver como isso se encaixa no seu pipeline, agende uma demo e vamos percorrer suas próprias imagens e configurações de execução.

Perguntas frequentes

O que é segurança de runtime de containers?

A segurança de runtime de containers é a proteção de containers enquanto estão em execução em produção, distinta de proteger a imagem em tempo de build ou no registry. Ela abrange apertar as primitivas de isolamento do kernel das quais um container depende — namespaces, cgroups, capabilities, seccomp e controle de acesso mandatório — e detectar e responder a comportamento malicioso em containers que já estão ao vivo. Ela existe porque uma imagem limpa ainda pode ser atacada em runtime por meio de vulnerabilidades recém-divulgadas, drift de filesystem ou uma fronteira de isolamento fraca.

O que é um container escape?

Um container escape ocorre quando um processo rompe o isolamento do seu container e ganha acesso ao sistema host ou a outros containers nele. Como os containers compartilham o kernel do host, um escape frequentemente significa comprometimento do host, e o comprometimento do host coloca em risco todos os outros containers naquele host. As causas comuns são executar containers privilegiados, montar caminhos sensíveis do host, expor o socket do Docker e vulnerabilidades de kernel sem patch.

Por que montar o socket do Docker é perigoso?

O daemon do Docker é controlado por meio de /var/run/docker.sock, e qualquer coisa que consiga alcançar esse socket pode comandar o daemon — inclusive iniciar um novo container que monta o filesystem do host e roda como root. Montar o socket dentro de um container, portanto, concede na prática a esse container o controle total do host e de todos os containers nele. Se uma ferramenta precisa dele, coloque o socket atrás de um proxy restritivo que exponha apenas as chamadas específicas necessárias, em vez de montá-lo diretamente.

O que o --privileged faz e por que evitá-lo?

A flag --privileged dá a um container quase todas as capabilities do Linux, desativa o confinamento padrão por seccomp e AppArmor e expõe os dispositivos do host. Na prática, ela remove a maioria das fronteiras que separam o container do host, o que torna trivial escapar para o host para um atacante que consiga execução de código dentro dele. Em vez de executar privilegiado, remova todas as capabilities com --cap-drop=ALL e adicione de volta apenas as específicas de que uma carga de trabalho genuinamente precisa.

Como detecto ataques em containers em execução?

Use detecção em runtime: monitoramento comportamental e de syscall que sinaliza um container fazendo algo anormal, como abrir um shell ou abrir uma conexão de rede inesperada; detecção de anomalias que aprende o comportamento normal de cada carga de trabalho e expõe os desvios; e detecção de drift que compara o container em execução com sua imagem original para pegar novos binários ou arquivos modificados. Combine tudo isso com logging centralizado que os containers não conseguem alcançar, para que você tenha uma trilha confiável para resposta a incidentes.

Bruno Baldo

Escrito por

Bruno Baldo

CMO

Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Continue lendo