Segurança de imagens Docker: escaneamento, hardening e proveniência
Guia prático de segurança de imagens Docker: escaneie vulnerabilidades, faça hardening com imagens mínimas, assine e proteja a cadeia de suprimentos.
Uma imagem Docker é o único artefato que viaja do laptop de um desenvolvedor, pelo CI, para um registry e até o que quer que a execute em produção. Isso faz da segurança de imagens Docker um dos investimentos de maior alavancagem que uma equipe pode fazer: faça o hardening da imagem uma vez e todo ambiente que a puxa herda o resultado; entregue uma imagem vulnerável ou adulterada uma vez e cada um deles herda isso em vez disso. A imagem é um sistema de arquivos congelado no qual o runtime confia por completo — ele não inspeciona o que há dentro, apenas executa. Decidir o que entra, verificar com escaneamento de imagens de contêiner e comprovar de onde veio é onde a segurança da cadeia de suprimentos de contêineres de fato começa.
Este é um mergulho profundo na imagem em si, parte do panorama mais amplo de segurança de Docker e contêineres. É deliberadamente focado em Docker e no registry: para ver como as mesmas preocupações se manifestam na camada de orquestração — admission control, pulls verificados, drift em runtime — consulte o guia complementar sobre segurança de imagens Kubernetes. Aqui ficamos com o build, o registry e o fluxo de trabalho local onde as imagens são criadas.
Anatomia do risco de imagem
Para proteger uma imagem de propósito, e não por hábito, ajuda dar nome aos distintos tipos de risco que ela carrega.
Pacotes do sistema operacional. A imagem base traz uma distribuição inteira de bibliotecas e utilitários de sistema. Eles acumulam CVEs com o tempo, e uma imagem base que estava limpa há dois meses quase certamente não está hoje. Pacotes do sistema operacional sem patch são a fonte isolada mais comum de vulnerabilidades de imagem.
Dependências da aplicação. Sua aplicação puxa bibliotecas open-source de npm, PyPI, Maven, módulos Go e suas dependências transitivas. Uma versão sabidamente vulnerável enterrada no fundo da árvore é tão explorável dentro de um contêiner quanto em qualquer outro lugar — e mais fácil de passar despercebida.
Layers e histórico. Uma imagem Docker não é um sistema de arquivos plano; é uma pilha de layers, cada um registrando um passo do build. Os layers são cacheados, endereçados por conteúdo e imutáveis. Isso é ótimo para reprodutibilidade e péssimo para qualquer coisa que você gostaria de não ter comitado, porque um arquivo adicionado em um layer persiste no histórico mesmo que um layer posterior o remova.
Segredos embutidos. Segredos acabam embutidos em imagens com mais frequência do que se admite: uma chave de API em uma linha ENV, um token .npmrc, uma chave SSH COPY-ada para uma dependência privada e nunca removida. Por causa do comportamento de layers acima, RUN rm secret.key não remove o segredo — apenas o esconde do sistema de arquivos final, deixando-o intacto em um layer anterior.
Proveniência. Por fim, a pergunta que a maioria das imagens não consegue responder por conta própria: de onde isto de fato veio? Sem proveniência você não consegue distinguir uma imagem que seu CI construiu e aprovou de uma que um invasor enviou ao seu registry sob a mesma tag.
Hardening na origem: imagens base mínimas e non-root
As vitórias de segurança mais baratas acontecem antes de qualquer scanner rodar, controlando o que entra na imagem em primeiro lugar.
Prefira imagens base mínimas ou distroless. Uma imagem distroless contém sua aplicação e suas dependências de runtime e quase nada mais — sem shell, sem gerenciador de pacotes, sem utilitários de uso geral. Isso encolhe a superfície de ataque diretamente (menos pacotes significa menos CVEs) e torna a pós-exploração muito mais difícil, porque um invasor que consegue executar código não encontra shell para pivotar. Um build multi-stage permite compilar em uma imagem com toolchain completo e entregar apenas o resultado, de modo que compiladores e ferramentas de build nunca cheguem à produção.
Execute como um usuário non-root. Se o processo não precisa de root, não conceda root a ele.
# Multi-stage build: compile in a full image, ship a minimal one
FROM golang:1.23 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/server
FROM gcr.io/distroless/static:nonroot
COPY --from=build /app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
A escolha da imagem base e as instruções do Dockerfile ao seu redor merecem ser tratadas como uma disciplina própria — veja boas práticas de segurança de Dockerfile para os detalhes de build, do pinning de versões à ordenação de layers para que segredos nunca entrem neles.
Escaneamento de vulnerabilidades: SCA em toda a imagem
Você não pode corrigir o que não consegue ver, e o escaneamento de imagens de contêiner é como você enxerga. Um escaneamento eficaz usa análise de composição de software (SCA) para inventariar tudo na imagem — tanto pacotes do sistema operacional quanto dependências da aplicação — e cruzar esse inventário com dados de vulnerabilidades. Escanear apenas o layer do sistema operacional ou apenas as dependências da aplicação deixa metade da imagem sem examinar; o escaneamento de vulnerabilidades de imagem precisa abranger o artefato inteiro.
Dois princípios tornam o escaneamento útil em vez de ruído.
Escaneie no build e continuamente. Escaneie no CI para que o desenvolvedor receba feedback no pull request que introduziu uma dependência ruim, enquanto a correção ainda é uma mudança de cinco minutos. Depois escaneie novamente no registry, de forma agendada, porque os dados de vulnerabilidades mudam mesmo quando sua imagem não muda. Uma imagem que passou limpa na semana passada pode falhar nesta semana quando um novo CVE crítico é divulgado contra um pacote que ela já contém. Só o rescan contínuo de imagens armazenadas captura isso.
Faça o build falhar diante de críticos com correção disponível. Um escaneamento que só emite um relatório é ignorado. Conecte o scanner ao pipeline para que novos achados de severidade crítica (e, quando apropriado, alta) quebrem o build, e delimite o gate a problemas que de fato têm correção disponível, para que as equipes não fiquem travadas em CVEs que não conseguem resolver.
# CI step: scan and fail on new fixable critical/high findings
rainforest image scan registry.example.com/app:$GIT_SHA \
--severity CRITICAL,HIGH \
--fail-on CRITICAL,HIGH \
--ignore-unfixed
Inspecionando layers e histórico em busca de segredos vazados
O escaneamento de vulnerabilidades encontra pacotes vulneráveis; não necessariamente encontra a chave privada que alguém copiou durante um build. Como os layers são imutáveis e cacheados, a detecção de segredos precisa olhar o histórico de layers, não apenas o sistema de arquivos final.
Os próprios metadados da imagem são o ponto de partida. O docker history mostra o comando por trás de cada layer, o que revela erros óbvios como um segredo passado como argumento de build ou definido em ENV:
docker history --no-trunc registry.example.com/app:$GIT_SHA
Para ir além, descompacte a imagem e inspecione o conteúdo de cada layer. Salvar uma imagem a expande em seus tarballs de layer individuais, de modo que um arquivo removido em um layer posterior ainda é recuperável — e detectável — no layer que o adicionou:
docker save registry.example.com/app:$GIT_SHA -o app.tar
mkdir app && tar -xf app.tar -C app
# each layer/*.tar is a filesystem diff you can search for keys, tokens, .env files
A detecção automatizada de segredos incorpora isso ao pipeline para que cada layer seja escaneado em busca de padrões de credenciais como parte do mesmo gate que roda o SCA — o que é muito mais confiável do que torcer para que um revisor perceba um token vazado em um diff. A remediação não é rm: é fazer o rebuild sem o segredo em nenhum layer, rotacionar a credencial exposta e usar build secret mounts para que o valor nunca chegue a entrar em uma imagem.
Tags versus digests imutáveis
Uma tag como app:1.4 é um ponteiro mutável. Quem puder fazer push para o registry pode reapontá-la para um conteúdo diferente, o que significa que uma imagem que você escaneou e aprovou pode silenciosamente se tornar uma imagem diferente sob o mesmo nome. Um digest — app@sha256:... — é a identidade da imagem endereçada por conteúdo e não pode mudar sem mudar a referência.
As regras práticas decorrem disso:
- Nunca faça deploy de `:latest` em produção. Com
:latestvocê não consegue dizer o que está rodando, não consegue reproduzir um deploy e não consegue amarrar uma carga de trabalho em execução a um resultado de escaneamento específico. - Fixe as referências de produção por digest. Um digest é reproduzível e evidencia adulterações; é a garantia mais forte de que o que você verificou é o que roda.
- Trate as tags de release como imutáveis. Uma vez que uma tag aponta para um digest, não a reaponte. Muitos registries conseguem impor a imutabilidade de tags diretamente.
Como essas imagens são armazenadas e servidas é um tema próprio; a segurança de container registry aborda registries privados, controle de acesso e imposição de imutabilidade em profundidade.
Assinatura de imagens e proveniência
O escaneamento diz o que há dentro de uma imagem. A assinatura de imagens e a proveniência dizem de onde ela veio e se se deve confiar nela.
A mecânica é direta. Quando seu pipeline constrói uma imagem, ele assina criptograficamente o digest resultante e registra attestations — declarações legíveis por máquina sobre como a imagem foi produzida: qual commit de origem, qual builder, quais passos rodaram. As próprias ferramentas do Docker ofereceram isso em várias formas ao longo dos anos (Docker Content Trust e, mais recentemente, assinaturas destacadas e attestations por meio de um fluxo estilo Notation e assinatura sem chave com transparency log no molde da abordagem cosign). O princípio subjacente é o mesmo independentemente da ferramenta: assine o digest no momento do build, verifique a assinatura antes de confiar na imagem.
Esse é o cerne do framework SLSA (Supply-chain Levels for Software Artifacts), que define níveis crescentes de integridade de proveniência para um build. A assinatura fecha uma brecha que nem o escaneamento nem o controle de acesso ao registry conseguem: mesmo que um invasor envie uma imagem maliciosa sob um nome legítimo, ela não carregará uma assinatura válida de uma chave que sua organização controla, e a verificação a rejeita. Como a assinatura e a verificação vivem no pipeline e não em um passo manual, a proveniência é imposta automaticamente para cada imagem, em vez de depender de alguém lembrar de checar.
Um SBOM para cada imagem
Um software bill of materials (SBOM) é um inventário completo e legível por máquina de tudo o que uma imagem contém — cada pacote do sistema operacional e cada dependência da aplicação, com versões. Gerar um por imagem e armazená-lo como attestation junto à imagem muda a forma como você responde à próxima grande vulnerabilidade.
Quando um CVE crítico atinge uma biblioteca amplamente usada, a pergunta "quais das nossas imagens entregam a versão afetada?" vira uma consulta a SBOMs armazenados em vez de uma rodada frenética de rebuilds e inspeção manual. O SBOM também é a entrada natural para o escaneamento contínuo: reavaliar um SBOM armazenado contra dados de vulnerabilidades atualizados é exatamente como um rescan de registry flagra uma imagem que estava limpa quando foi construída. Builders modernos conseguem emitir um SBOM como parte do build, de modo que ele carrega as mesmas garantias de proveniência que a própria imagem. É aqui que a segurança de imagens encontra a análise de composição de software de forma mais direta — o SBOM é o inventário compartilhado do qual ambas dependem.
Da imagem ao que a executa
Tudo acima produz um artefato confiável; algo ainda precisa recusar os não confiáveis. Em um fluxo de trabalho centrado em Docker, essa imposição vive no CI (faça o build falhar) e no registry (bloqueie ou coloque em quarentena imagens que reprovam na política). Quando essas imagens rodam sob um orquestrador, os mesmos sinais — uma assinatura válida, um escaneamento aprovado, uma referência por digest em vez de uma tag mutável — tornam-se entradas para o admission control, que pode negar qualquer pod cuja imagem não atenda à política antes mesmo de ser agendado. O guia de segurança de imagens Kubernetes cobre esse gate em detalhe. O ponto importante é a continuidade: a assinatura que você anexa e o SBOM que você gera no momento do build são exatamente a evidência que a camada de admissão checa no momento do deploy, de modo que a segurança de imagens e a imposição em tempo de deploy são duas pontas de uma mesma corrente.
Esse é o padrão em cada seção aqui. Segurança de imagens não é uma ferramenta única, mas uma sequência de checkpoints — imagem base, build, escaneamento, verificação de segredos, assinatura, SBOM, armazenamento, pinning — e uma fraqueza em qualquer elo compromete o resto. Quanto mais cedo nessa sequência um problema é capturado, mais barato é corrigi-lo, e é por isso que boa parte do trabalho pertence ao CI e ao registry, e não ao pós-deploy.
Como a Rainforest ajuda
Proteger essa corrente inteira é mais fácil quando os checkpoints compartilham uma única visão do seu software. A Rainforest reúne segurança de contêineres e análise de composição de software para que você possa escanear imagens Docker tanto em pacotes do sistema operacional quanto em dependências da aplicação, revelar segredos embutidos no histórico de layers, gerar um SBOM por imagem e acompanhar os achados do pull request até o registry. Como a mesma plataforma também avalia as dependências que suas aplicações puxam e a infraestrutura como código que as implanta, uma imagem e tudo ao seu redor são avaliados como uma única cadeia de suprimentos conectada, e não isoladamente — que é como as falhas de cadeia de suprimentos de software, rastreadas como a categoria A03 no OWASP Top 10 (2025), de fato chegam à produção.
Se você está estruturando sua segurança de imagens Docker, agende uma demo e vamos percorrer escaneamento, hardening e proveniência para a sua cadeia de suprimentos de imagens de ponta a ponta.
Perguntas frequentes
Como faço para escanear uma imagem Docker em busca de vulnerabilidades?
Use um scanner de imagens de contêiner apoiado em análise de composição de software (SCA) que inventarie tanto pacotes do sistema operacional quanto dependências da aplicação e os cruze com CVEs conhecidos — escanear apenas um layer deixa o outro sem examinar. Execute o escaneamento no CI para que os desenvolvedores recebam feedback na mudança que introduziu o problema, e execute-o novamente no registry de forma agendada para que imagens já publicadas sejam reavaliadas à medida que novas vulnerabilidades são divulgadas. Configure o pipeline para falhar diante de novos achados de severidade crítica (e tipicamente alta) e delimite o gate a problemas que tenham correção disponível, para que ele permaneça acionável.
O que é assinatura de imagens e por que importa?
A assinatura de imagens anexa uma assinatura criptográfica ao digest de uma imagem, e as attestations de proveniência registram como a imagem foi construída (o modelo SLSA). Antes de qualquer coisa confiar na imagem, ela verifica essa assinatura. Isso importa porque o escaneamento e o controle de acesso ao registry não conseguem dizer que uma imagem de fato veio do seu pipeline — um invasor que consiga fazer push para o seu registry poderia substituir uma imagem maliciosa sob um nome legítimo. Uma assinatura válida de uma chave que sua organização controla, checada no momento da verificação, é o que captura exatamente essa substituição.
Devo usar tags ou digests de imagem?
Use digests imutáveis (app@sha256:...) para qualquer coisa que você faça deploy em produção. Uma tag é um ponteiro mutável que pode ser reapontado para um conteúdo diferente, então uma imagem que você escaneou e aprovou pode silenciosamente se tornar uma imagem diferente sob o mesmo nome; um digest é endereçado por conteúdo e não pode mudar sem que a referência mude. Nunca faça deploy de :latest, porque isso torna os deploys não reproduzíveis e impossíveis de amarrar a um escaneamento específico. Tags de release legíveis por humanos são adequadas por conveniência, desde que você as trate como imutáveis e fixe o deploy real por digest.
O que é uma imagem distroless?
Uma imagem distroless é uma imagem base mínima que contém apenas sua aplicação e suas dependências de runtime — sem shell, sem gerenciador de pacotes e sem nenhum dos utilitários de uso geral que uma distribuição Linux normal traz. Isso encolhe a superfície de ataque (menos pacotes significa menos CVEs para um scanner encontrar) e torna a pós-exploração muito mais difícil, porque um invasor que obtenha execução de código não tem shell para pivotar. Combine-a com um usuário non-root e um build multi-stage para que compiladores e ferramentas de build fiquem inteiramente fora da imagem final.
Como encontro segredos embutidos em uma imagem?
Olhe o histórico de layers, não apenas o sistema de arquivos final, porque um segredo adicionado em um layer sobrevive ali mesmo que um layer posterior o apague. Comece com docker history --no-trunc para capturar segredos passados por argumentos de build ou ENV, depois use docker save para descompactar a imagem em seus tarballs por layer e procurar em cada um por chaves, tokens e arquivos .env. Melhor ainda, rode detecção automatizada de segredos no seu pipeline para que cada layer seja escaneado como parte do mesmo gate do SCA. Se encontrar um, faça o rebuild sem o segredo em nenhum layer, rotacione a credencial exposta e use build secret mounts para que o valor nunca mais entre em uma imagem.

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

Segurança de containers Docker: o guia completo
Guia completo de segurança de containers Docker: modelo de ameaças, superfície de ataque do ciclo de vida, hardening do daemon e boas práticas.

Boas práticas de segurança em Dockerfile
Boas práticas de segurança em Dockerfile: fixe imagens base confiáveis, rode como non-root, use multi-stage, mantenha segredos fora e escaneie tudo no CI.

Segurança de container registry: protegendo a distribuição de imagens
A segurança de container registry protege o ponto onde imagens são armazenadas e obtidas. Veja controle de acesso, assinatura, varredura e proveniência.
