Alternar tema

Segurança de imagens Docker: varredura e correção com Trivy e integração ao CI/CD

Easton editorial illustration: deployment checkpoint lane

Em 10 de dezembro de 2021, a curva de alertas no painel de monitoramento disparou. Alguém publicou no grupo de operações o identificador de um CVE: CVE-2021-44228, a vulnerabilidade Log4Shell que depois abalaria todo o setor de tecnologia. Mais de dez microsserviços usavam imagens base afetadas, e a equipe inteira passou a madrugada atualizando as imagens e fazendo uma nova implantação às pressas.

Na retrospectiva, o chefe fez uma pergunta: “Como é que nem sabemos quais vulnerabilidades existem nas imagens que usamos?”

Uma pesquisa da NSFOCUS mostrou que 76% das imagens no Docker Hub têm vulnerabilidades conhecidas. Aquela imagem python:3.9 que você usa? nginx:latest? É bem possível que esconda dezenas de CVEs.

Você provavelmente quer saber: como descobrir quais vulnerabilidades existem em uma imagem? Como corrigi-las? Como fazer a detecção automática no fluxo de CI/CD e evitar que uma imagem vulnerável chegue à produção?

Levei dois anos enfrentando problemas em produção até encontrar respostas práticas para essas perguntas. Neste artigo, você vai aprender passo a passo:

  • Como usar Trivy e outras ferramentas para verificar rapidamente vulnerabilidades em imagens Docker
  • Como corrigir vulnerabilidades de forma sistemática, indo muito além de apenas “atualizar a versão da imagem”
  • Como integrar a varredura automática a plataformas de CI/CD como GitHub Actions e GitLab CI

Todos os comandos e arquivos de configuração são exemplos práticos que você pode copiar e executar. Este guia deve poupar bastante tempo e alguns tropeços.

"Um relatório de pesquisa da NSFOCUS, publicado em março de 2018, mostrou que mais de três quartos (76%) das imagens selecionadas aleatoriamente no Docker Hub tinham vulnerabilidades conhecidas."

- Relatório de pesquisa da NSFOCUS

Visão geral das ameaças à segurança de imagens Docker

Quais problemas de segurança uma imagem Docker pode ter?

Para ser sincero, quando comecei a trabalhar com contêineres, também achava que uma imagem Docker era apenas um “programa empacotado”: se funcionasse, estava tudo certo. Só depois de uma varredura que levou três dias em produção percebi que as vulnerabilidades de uma imagem se dividem em várias categorias, e cada uma delas pode dar bastante trabalho.

Vulnerabilidades em pacotes do sistema operacional — São as mais comuns. Bibliotecas como OpenSSL, glibc e curl, presentes nas imagens base Alpine e Ubuntu, recebem novas vulnerabilidades de tempos em tempos. As falhas graves do OpenSSL 3.0.x em 2022, por exemplo, afetaram muitas imagens.

Vulnerabilidades em dependências da aplicação — Estas são mais discretas. Seu projeto Python depende de Flask, Flask depende de Werkzeug, e uma determinada versão do Werkzeug tem uma falha de execução de código. Atualizar a versão do Python basta para ficar seguro? Não necessariamente. As vulnerabilidades escondidas na árvore de dependências podem passar despercebidas. O Log4j é o exemplo clássico: muitos projetos Java nem sabiam que o utilizavam.

Configurações incorretas e vazamento de informações sensíveis — Para ganhar tempo, alguns desenvolvedores escrevem a senha do banco de dados diretamente no Dockerfile ou empacotam o diretório .git porque se esqueceram de removê-lo. Outros executam o contêiner como root e distribuem privilégios com uma generosidade digna da chave de casa.

Riscos da cadeia de suprimentos — São os mais difíceis de prevenir. Você pode baixar do Docker Hub uma imagem aparentemente normal e descobrir depois que alguém inseriu nela um minerador de criptomoedas ou um backdoor. Em 2018, uma pesquisa encontrou várias “imagens maliciosas” no Docker Hub, criadas justamente para fisgar quem fazia pull sem verificar nada.

Por que não se deve confiar cegamente nas imagens do Docker Hub?

Na primeira vez que vi esse número de 76%, fiquei realmente surpreso.

Você pode pensar que esse dado já está velho. O problema é que essas imagens antigas continuam sendo usadas. Além disso, muitas imagens “oficiais” não são atualizadas em tempo real. A tag python:3.9 que você encontrou pode ter sido criada há seis meses e conter pacotes do sistema já obsoletos.

Para complicar, a qualidade das imagens no Docker Hub varia muito. Algumas são mantidas por desenvolvedores individuais e podem ficar seis meses sem atualização; outras são chamadas de “oficiais”, mas foram apenas enviadas por uma empresa. Não existe um padrão unificado de auditoria de segurança, então usá-las sem verificar é contar com a sorte.

Um colega meu baixou do Docker Hub uma imagem com Node.js porque era mais conveniente. Uma varredura posterior encontrou mais de 30 vulnerabilidades de alto risco. Quando perguntou ao autor, recebeu a resposta: “Essa imagem não é mantida há dois anos; faça as alterações você mesmo.” Foi difícil saber se ria ou chorava.

Por isso, minha regra hoje é simples: sempre faça uma varredura em qualquer imagem baixada do Docker Hub antes de usá-la, mesmo quando ela tiver a tag “oficial”.

Comparação e escolha das principais ferramentas de varredura de imagens

Trivy: a ferramenta open source que mais recomendo

Existem muitas ferramentas de segurança para verificar imagens Docker, mas hoje uso quase sempre o Trivy. Não porque as demais sejam ruins, e sim porque o Trivy equilibra muito bem facilidade de uso e funcionalidade.

Na primeira vez que o utilizei, sua velocidade me impressionou. A primeira varredura de uma imagem com algumas centenas de MB levou cerca de 10 segundos; as seguintes, apenas alguns segundos. Mais importante: não é preciso manter um banco de dados local nem configurar um serviço adicional. Basta instalar e usar.

O que o Trivy consegue detectar? Para ser sincero, mais coisas do que eu esperava:

  • Detecção de vulnerabilidades: oferece suporte a pacotes de vários sistemas operacionais (Alpine, Ubuntu, Debian, CentOS etc.) e a dependências de aplicações (npm, pip, Maven, Go Modules etc.)
  • Varredura de configurações incorretas: identifica problemas de segurança em Dockerfiles e arquivos de configuração do Kubernetes
  • Detecção de vazamento de secrets: avisa se chaves, senhas ou outras informações sensíveis foram empacotadas na imagem por engano
  • Conformidade de licenças: também verifica as licenças open source das dependências para evitar riscos jurídicos

O que mais me agrada é que o Trivy já está integrado a plataformas populares como GitHub Actions e Harbor. Você não precisa inventar uma solução de integração: o caminho já está pronto.

Uma visão rápida de outras ferramentas

Snyk — É um produto comercial com recursos realmente abrangentes. Pode ser integrado diretamente à IDE e alertar, enquanto você programa, sobre vulnerabilidades nas dependências. Também consegue criar PRs de correção automaticamente. O problema é que a versão gratuita tem muitas limitações, e o uso aprofundado custa dinheiro. É mais indicado para grandes empresas com orçamento disponível.

Clair — É o mecanismo open source de varredura do registry Quay e permite ampla personalização. Mas, para ser sincero, sua configuração é mais complexa. Ele coleta informações de CVEs das equipes de segurança de várias distribuições Linux e se concentra na detecção de ameaças. Se sua equipe tem engenheiros de segurança dedicados e quer uma solução altamente personalizável, o Clair é uma boa opção. Para uma equipe de desenvolvimento comum, porém, a curva de aprendizado é alta.

Anchore — É uma solução empresarial com suporte ao gerenciamento de políticas. Você pode, por exemplo, criar uma regra como: “Se houver uma vulnerabilidade CRITICAL, impeça a implantação.” Ela serve para cenários com requisitos rigorosos de conformidade, como os setores financeiro e de saúde. O custo é uma configuração e manutenção mais pesadas.

Docker Scout / Hardened Images (DHI) — É um novo produto oficial da Docker, lançado em maio de 2025, que promete chegar perto de zero CVEs e reduzir o tamanho das imagens em até 95%. Analisei a solução técnica: ela usa um runtime distroless e parece muito promissora. Como o produto ainda é recente e seu ecossistema está em construção, vale acompanhar sua evolução.

Minha recomendação

Se você é desenvolvedor individual ou trabalha em uma equipe pequena ou média, use o Trivy diretamente. É gratuito, fácil e oferece os recursos necessários. Um comando instala, outro executa a varredura, e você começa em 10 minutos.

Se você trabalha em uma grande empresa, com requisitos elevados de segurança e conformidade e orçamento suficiente, vale considerar o Snyk. Seu banco de vulnerabilidades é atualizado rapidamente, o suporte é profissional e as integrações com ferramentas de desenvolvimento são profundas.

Se sua equipe tem engenheiros de segurança dedicados e quer uma solução open source amplamente personalizável, vale estudar o Clair. Apenas esteja preparado para investir tempo na configuração.

Se a prioridade for segurança máxima e imagens mínimas, acompanhe o desenvolvimento das Docker Hardened Images. Elas podem se tornar a solução padrão da próxima geração.

Na minha prática, uso Trivy no desenvolvimento cotidiano e no CI/CD para obter feedback rápido; antes da implantação em produção, faço uma segunda varredura com o Clair integrado ao Harbor. É uma dupla proteção.

Tutorial prático de Trivy

Instalação e uso básico

Instalar o Trivy é tão simples que, na primeira vez, até parece estranho. Se você usa macOS:

brew install trivy

No Linux, você pode baixar diretamente o binário ou usar um gerenciador de pacotes. A página de releases no GitHub traz instruções detalhadas: https://github.com/aquasecurity/trivy/releases

Depois de instalar, faça imediatamente uma varredura para testar:

# Verifica uma imagem do Docker Hub
trivy image python:3.9

# Verifica uma imagem criada localmente
trivy image myapp:latest

# Verifica uma imagem salva em um arquivo tar
trivy image --input ruby-3.1.tar

Na primeira execução, o Trivy baixa automaticamente o banco de vulnerabilidades (trivy-db), com algumas dezenas de MB. É preciso esperar um pouco; depois do download, as varreduras ficam muito rápidas.

Os resultados são exibidos por nível de gravidade:

  • CRITICAL (crítica): deve ser corrigida imediatamente e pode permitir o controle total do sistema
  • HIGH (alta): deve ser corrigida o quanto antes e pode ser explorada em um ataque
  • MEDIUM (média): a correção é recomendada, pois existe algum risco de segurança
  • LOW (baixa): tem prioridade menor e pode entrar no planejamento

Cada vulnerabilidade mostra o identificador CVE, o nome do pacote afetado, a versão atual e a versão corrigida, quando houver.

Opções avançadas para aproveitar melhor o Trivy

No trabalho real, talvez você não queira ver todas as vulnerabilidades, especialmente as de baixo risco que ainda não podem ser corrigidas. Para isso, existem algumas opções avançadas:

Mostre apenas vulnerabilidades altas e críticas:

trivy image --severity HIGH,CRITICAL nginx:latest

Uso muito essa opção no CI/CD. Exigir a correção de todas as vulnerabilidades não é realista; resolver primeiro as mais graves é a prioridade.

Ignore vulnerabilidades ainda sem correção:

trivy image --ignore-unfixed redis:latest

Algumas vulnerabilidades ainda não têm patch oficial, e não há muito o que você possa fazer. Com esse parâmetro, o Trivy mostra apenas as que já têm solução, permitindo concentrar esforço no que pode ser resolvido.

Retorne um código de saída diferente de zero ao encontrar uma vulnerabilidade crítica:

trivy image --exit-code 1 --severity CRITICAL myapp:latest

Isso é muito útil. Em um pipeline de CI/CD, quando uma vulnerabilidade crítica é encontrada, o comando retorna um código diferente de zero e o build falha. É como colocar uma barreira de segurança diante da imagem: uma imagem vulnerável simplesmente não chega à produção.

Gere uma saída JSON para integrar a outras ferramentas:

trivy image -f json -o results.json myapp:latest

Se você quiser importar o resultado para uma plataforma de segurança ou fazer outro processamento automático, o formato JSON é conveniente.

Faça a varredura em um ambiente offline:

trivy image --skip-db-update myapp:latest

Algumas redes corporativas não têm acesso à internet. Nesse caso, baixe o banco de vulnerabilidades em uma máquina conectada, copie-o para a rede interna e use esse parâmetro para evitar uma tentativa de atualização.

Como interpretar o resultado: no que prestar atenção

Na primeira vez que verifiquei uma imagem de produção, a tela se encheu com mais de 100 vulnerabilidades. Meu primeiro pensamento foi: quanto tempo vamos levar para corrigir tudo isso?

Com a experiência, entendi que existem alguns atalhos para interpretar o resultado:

Priorize vulnerabilidades que já têm uma versão corrigida. Se a coluna Fixed Version mostrar none ou estiver vazia, ainda não existe patch e você não pode fazer muita coisa. Resolva primeiro as vulnerabilidades para as quais já há correção.

Concentre-se em CRITICAL e HIGH. Vulnerabilidades LOW e MEDIUM podem ser adiadas quando o serviço não está exposto à internet. As CRITICAL, porém, exigem correção imediata: muitas vezes existe código de exploit público que um invasor pode usar diretamente.

Consulte os detalhes do CVE. Se tiver dúvidas sobre uma vulnerabilidade, procure o identificador CVE em https://cve.mitre.org/ e examine o problema, o alcance do impacto e a dificuldade de exploração. Às vezes, uma falha aparentemente assustadora depende de condições muito específicas para ser explorada.

Entenda como o Trivy funciona. O Trivy baixa um banco de vulnerabilidades, que na prática é um arquivo JSON com falhas conhecidas de vários pacotes, e o compara à lista de pacotes da imagem, obtida a partir do banco de dados do gerenciador de pacotes. Se o nome e a versão de um pacote corresponderem a uma vulnerabilidade conhecida, ele gera um alerta.

Por isso, podem existir falsos positivos. O pacote vulnerável pode estar na imagem, mas o código talvez nunca chame a função afetada; ainda assim, o Trivy vai alertar. Nesse caso, é preciso avaliar o risco considerando o código real.

Como corrigir vulnerabilidades de forma sistemática

Comece escolhendo a imagem base certa

Muitas vezes, corrigir vulnerabilidades não significa “consertar”, e sim “trocar”. Encontrou dezenas de falhas em pacotes do sistema? Em vez de atualizar uma por uma, é muito mais eficiente mudar para uma imagem base mais segura.

Minha equipe costumava usar Alpine Linux como imagem base por causa de seu tamanho reduzido, apenas 5,87 MB. Depois descobrimos que o Alpine também tem seus problemas: ele usa a biblioteca padrão musl em vez da glibc mais comum, o que às vezes causa incompatibilidades. E, embora seja pequeno, isso não significa que esteja livre de vulnerabilidades.

Hoje prefiro usar imagens Distroless. Elas têm apenas 3,06 MB, são menores que Alpine e foram reduzidas ao essencial: não incluem shell, gerenciador de pacotes nem ferramentas desnecessárias.

Por que isso é mais seguro? É simples. Mesmo que um invasor encontre uma vulnerabilidade na sua aplicação, ele não conseguirá executar comandos de shell dentro do contêiner, porque não existe shell. A superfície de ataque fica reduzida ao mínimo.

As imagens Distroless do Google têm versões para várias linguagens:

# Aplicação Python
FROM gcr.io/distroless/python3

# Aplicação Node.js
FROM gcr.io/distroless/nodejs

# Aplicação Go (se for compilada estaticamente, pode usar a versão static)
FROM gcr.io/distroless/static

É claro que Distroless também tem um inconveniente: a depuração é difícil, pois nem comandos básicos como ls e cat estão disponíveis. Minha abordagem é usar uma imagem comum no ambiente de desenvolvimento para facilitar a depuração e mudar para Distroless em produção para garantir a segurança.

Em 2025, a Docker lançou as Hardened Images (DHI), uma opção ainda mais radical que promete quase zero CVEs e redução adicional de até 95% no tamanho. O ecossistema ainda não amadureceu, mas vale muito a pena acompanhar: talvez seja o padrão da próxima geração.

Como atualizar dependências para corrigir vulnerabilidades

Trocar a imagem base não basta. Também é preciso cuidar das dependências da aplicação. Estas são algumas técnicas práticas:

Método 1: atualize a versão da imagem base

# Não use latest: é uma referência vaga demais
FROM python:3.9

# Use uma versão secundária específica e atualize-a regularmente
FROM python:3.11.7

Muita gente usa a tag latest por conveniência, mas esse é um hábito ruim. A imagem latest pode ficar meses sem atualização, com pacotes do sistema já obsoletos. Use uma versão específica e verifique ativamente, uma vez por mês, se há uma versão secundária mais recente.

Método 2: atualize os pacotes do sistema no Dockerfile

FROM ubuntu:22.04

# Atualiza todos os pacotes do sistema durante o build da imagem
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

Observe o detalhe: colocar update, upgrade e clean em uma única instrução RUN reduz o número de camadas da imagem. A remoção final do cache do apt ainda economiza algumas dezenas de MB.

Método 3: atualize as dependências da aplicação

Este é o caso mais comum. Se o Trivy encontrar uma vulnerabilidade no Flask, altere a versão em requirements.txt:

# Antes
Flask==2.0.1

# Depois (supondo que a falha tenha sido corrigida na 2.3.0)
Flask==2.3.0

Há uma armadilha: atualizar diretamente o Flask pode causar problemas de compatibilidade. O ideal é testar primeiro em um ambiente de homologação e só enviar para produção depois de confirmar que tudo funciona.

Uma abordagem mais segura é atualizar apenas a versão de patch. Se o Flask 2.0.1 tiver uma falha, tente primeiro a versão 2.0.x mais recente, em vez de saltar diretamente para a 2.3.0.

Boas práticas que não devem ser ignoradas

Além de corrigir vulnerabilidades específicas, alguns bons hábitos ajudam a manter as imagens seguras no longo prazo:

Use builds multi-stage:

# Estágio de build
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# Estágio de runtime (somente o binário compilado)
FROM gcr.io/distroless/static
COPY --from=builder /app/myapp /
CMD ["/myapp"]

Assim, a imagem final não contém o compilador Go, o código-fonte nem arquivos intermediários. Ela fica limpa e com uma superfície de ataque muito menor.

Não execute como root:

RUN useradd -m myuser
USER myuser

Muitas imagens executam a aplicação como root por padrão, o que é extremamente perigoso. Depois de comprometer a aplicação, o invasor ganha privilégios de root e pode fazer o que quiser. Crie um usuário comum e execute a aplicação com essa identidade: é muito mais seguro.

Recrie as imagens regularmente:

Esse ponto é fácil de esquecer. Seu código pode ficar seis meses sem alterações, mas os pacotes da imagem base continuam recebendo patches. Faça um novo build pelo menos uma vez por mês para incorporar as correções de segurança mais recentes.

Nossa equipe configurou uma tarefa agendada que recria todas as imagens de produção aos domingos e executa uma varredura. Se houver algum problema, podemos encontrá-lo e corrigi-lo na segunda-feira.

Use .dockerignore para não empacotar arquivos sensíveis:

.git
.env
*.log
secrets/

Se um arquivo .env entrar na imagem por engano, a senha do banco de dados será exposta. O .dockerignore funciona como o .gitignore: impede que arquivos sensíveis sejam empacotados.

Nunca use a tag latest:

Vale repetir. FROM python:latest é uma bomba-relógio: você não sabe exatamente qual versão será baixada nem se ela tem vulnerabilidades. Use uma tag explícita como FROM python:3.11.7-slim, que seja previsível e rastreável.

Como automatizar a varredura de segurança no CI/CD

Integração com GitHub Actions em cinco minutos

Fazer a varredura manualmente dá trabalho e é fácil esquecer. A abordagem mais confiável é integrá-la ao CI/CD, verificando cada commit ou build automaticamente.

Integrar o Trivy ao GitHub Actions é surpreendentemente simples. Crie .github/workflows/docker-scan.yml no repositório:

name: Docker Security Scan

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Build Docker image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          format: 'table'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'  # O build falha ao encontrar vulnerabilidades graves

      - name: Upload scan results
        if: always()
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

O que essa configuração faz?

  • É executada automaticamente em cada push para as branches main ou develop e em cada PR para main
  • Cria a imagem Docker usando o SHA do commit como tag, para que cada build seja único
  • Verifica a imagem com Trivy, considerando apenas vulnerabilidades CRITICAL e HIGH
  • Se encontrar uma vulnerabilidade grave, exit-code: '1' faz o workflow falhar e impede o merge do commit
  • Envia os resultados à aba Security do GitHub para facilitar a consulta

Depois de configurar, faça um push para testar. O resultado aparecerá na aba GitHub Actions. Se houver vulnerabilidades, o build ficará vermelho e não poderá ser incorporado à branch principal. É uma barreira automática de segurança para seu código.

Integração com GitLab CI/CD: igualmente simples

Se você usa GitLab, a integração é parecida. Crie ou altere .gitlab-ci.yml na raiz do repositório:

stages:
  - build
  - test
  - security

build_image:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

security_scan:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  allow_failure: false
  dependencies:
    - build_image

Observe a linha allow_failure: false: uma falha na varredura de segurança faz todo o pipeline falhar. Se você não quiser uma política tão rígida, pode usar allow_failure: true; assim, uma vulnerabilidade gera apenas um aviso e não bloqueia a implantação.

Ainda assim, recomendo manter false no pipeline de produção. O ambiente de desenvolvimento pode ser mais flexível, mas a produção não deve fazer concessões.

Harbor como segunda linha de defesa

Se sua empresa usa o Harbor como registry privado de imagens — algo comum em grandes empresas — o processo fica ainda mais fácil. Desde a versão v1.2, o Harbor integra Trivy e Clair e pode verificar automaticamente cada imagem enviada.

Nas configurações de projeto do Harbor, você pode definir políticas de varredura:

  • Executar uma varredura automaticamente depois do push da imagem
  • Verificar todas as imagens diariamente, caso novas vulnerabilidades sejam descobertas
  • Definir um limite de vulnerabilidades, impedindo, por exemplo, o pull de imagens com falhas CRITICAL

Nossa equipe usa a seguinte política:

  1. No ambiente de desenvolvimento, o push para o Harbor dispara automaticamente uma varredura do Trivy
  2. Quando encontra uma vulnerabilidade HIGH ou superior, o Harbor adiciona à imagem a tag “com vulnerabilidades”
  3. No ambiente de produção, um admission webhook do cluster K8s rejeita a implantação de imagens com essa tag

Assim, mesmo que alguém contorne o CI/CD e tente fazer uma implantação direta, o Harbor bloqueia a imagem na última barreira.

Sugestão de um fluxo completo de varredura de segurança

Reunindo tudo, um fluxo completo de segurança de imagens deve ser assim:

Desenvolvimento:

  • Integre plugins do Snyk ou Trivy à IDE para identificar vulnerabilidades nas dependências enquanto programa
  • Depois de criar a imagem localmente, execute manualmente trivy image

Build:

  • Use GitHub Actions ou GitLab CI para verificar automaticamente cada nova imagem
  • Ao encontrar uma vulnerabilidade CRITICAL, interrompa o processo imediatamente e impeça o merge
  • Envie os resultados ao Security Dashboard para que a equipe acompanhe as tendências

Repositório:

  • Faça uma segunda varredura no Harbor ou em outro registry de imagens, porque o CI/CD pode deixar algo passar ou uma nova vulnerabilidade pode ser divulgada
  • Defina políticas que impeçam o pull de imagens de alto risco

Runtime:

  • Verifique semanalmente as imagens em execução na produção
  • Ao encontrar uma nova vulnerabilidade, gere um alerta e planeje a correção

Revisão periódica:

  • Revise mensalmente a situação das correções
  • Atualize as políticas de varredura e os limites de vulnerabilidade

O fluxo parece complexo, mas, depois de configurado, funciona automaticamente. Nossa equipe levou cerca de um Sprint (duas semanas) da configuração à operação estável, em troca de proteção contínua.

Para ser sincero, desde que configuramos esse fluxo, durmo com mais tranquilidade. Pelo menos não preciso temer a descoberta súbita de uma grande vulnerabilidade em imagens que já estavam comprometidas havia tempo.

Conclusão

Voltando à história do Log4Shell no início do artigo: se já tivéssemos esse fluxo de varredura de segurança de imagens, a vulnerabilidade teria sido encontrada no CI/CD e nunca chegaria à produção. Não haveria aquela madrugada tensa nem a pergunta incômoda do chefe.

Segurança de imagens Docker não é um assunto misterioso. Ela se resume a três pontos:

  • Use Trivy e outras ferramentas para verificar as vulnerabilidades da imagem — A instalação é simples, a execução é rápida e os recursos são suficientes
  • Corrija as vulnerabilidades de forma sistemática — Escolha uma imagem base segura, atualize as dependências e siga boas práticas
  • Automatize a varredura no CI/CD — A integração ao GitHub Actions ou GitLab CI leva cinco minutos

Para ser sincero, descobrir que 76% das imagens do Docker Hub têm vulnerabilidades foi assustador no início. Pensando melhor, isso também mostra que a maioria das equipes ainda não dá a devida atenção ao problema. Se você agir agora, já pode fazer melhor do que esses 76% — e isso é um bom avanço.

Minha sugestão é não tentar corrigir todas as vulnerabilidades de uma só vez, porque isso não é realista. Comece pelo mais simples:

  1. Antes de encerrar o dia: instale o Trivy, faça uma varredura na imagem Docker do projeto e veja quantas vulnerabilidades existem
  2. Ainda nesta semana: corrija as vulnerabilidades CRITICAL; talvez baste atualizar a versão da imagem base
  3. No próximo Sprint: integre o Trivy ao CI/CD e bloqueie a implantação quando houver uma vulnerabilidade grave
  4. Neste mês: defina uma baseline de segurança para as imagens e revise-a regularmente

Segurança de contêineres é um processo contínuo, não uma tarefa que se resolve de uma vez por todas. Depois de estabelecer o fluxo, porém, a manutenção exige pouco esforço. Nossa equipe faz varreduras automáticas toda semana, examina os problemas na reunião semanal e geralmente resolve tudo em meia hora.

Uma última vez: verifique as imagens de produção. Verifique qualquer imagem baixada do Docker Hub. Não espere acontecer um incidente para se arrepender, porque então será tarde demais.

Se você tem experiências práticas ou histórias sobre problemas de segurança com Docker, compartilhe nos comentários. Podemos aprender juntos e tornar as aplicações em contêiner mais seguras.

Fluxo completo para verificar e corrigir a segurança de imagens Docker

Etapas completas da instalação do Trivy à integração com CI/CD, incluindo varredura, correção e automação

⏱️ Estimated time: 2 hr

  1. 1

    Step 1: Instale a ferramenta de varredura Trivy

    Instale a ferramenta de varredura Trivy:
    • No macOS: brew install trivy
    • No Linux: baixe o binário na página de releases do GitHub ou instale com um gerenciador de pacotes
    • Download: https://github.com/aquasecurity/trivy/releases
    • Na primeira execução, o banco de vulnerabilidades será baixado automaticamente (trivy-db, com algumas dezenas de MB)
  2. 2

    Step 2: Faça uma varredura básica das vulnerabilidades da imagem

    Faça uma varredura básica das vulnerabilidades da imagem:
    • Imagem do Docker Hub: trivy image python:3.9
    • Imagem local: trivy image myapp:latest
    • Arquivo tar: trivy image --input ruby-3.1.tar

    Os resultados são classificados por gravidade:
    • CRITICAL (corrija imediatamente)
    • HIGH (corrija o quanto antes)
    • MEDIUM (correção recomendada)
    • LOW (pode entrar no planejamento)
  3. 3

    Step 3: Configure opções avançadas de varredura

    Configure opções avançadas de varredura:
    • Mostre apenas vulnerabilidades altas e críticas: trivy image --severity HIGH,CRITICAL nginx:latest
    • Ignore vulnerabilidades ainda sem correção: trivy image --ignore-unfixed redis:latest
    • Retorne um código de saída diferente de zero ao encontrar vulnerabilidades críticas (para CI/CD):
    trivy image --exit-code 1 --severity CRITICAL myapp:latest
    • Gere saída JSON: trivy image -f json -o results.json myapp:latest
  4. 4

    Step 4: Corrija as vulnerabilidades de forma sistemática

    Corrija as vulnerabilidades de forma sistemática:

    Escolha uma imagem base segura:
    • Use imagens Distroless (gcr.io/distroless/python3/nodejs/static, com apenas 3,06 MB, sem shell nem gerenciador de pacotes)
    • Ou as Docker Hardened Images de 2025 (quase zero CVEs)

    Atualize a versão da imagem base:
    • Use uma versão específica (python:3.11.7), não latest

    Atualize os pacotes do sistema no Dockerfile:
    • RUN apt-get update && apt-get upgrade -y && apt-get clean && rm -rf /var/lib/apt/lists/*

    Atualize as dependências da aplicação:
    • Altere requirements.txt e outros arquivos de dependências, priorizando atualizações de patch
  5. 5

    Step 5: Integre a varredura automática ao GitHub Actions

    Crie o arquivo .github/workflows/docker-scan.yml e configure:
    • Disparo em push/pull_request
    • Build da imagem Docker
    • Varredura com aquasecurity/trivy-action
    • severity: 'CRITICAL,HIGH' e exit-code: '1' (o build falha ao encontrar vulnerabilidades graves)
    • Envio dos resultados à aba Security do GitHub
  6. 6

    Step 6: Integre ao GitLab CI/CD

    Crie ou altere .gitlab-ci.yml e configure:
    • stages com build, test e security
    • Uso da imagem aquasec/trivy:latest no estágio security
    • Execução de trivy image --exit-code 1 --severity HIGH,CRITICAL
    • allow_failure: false (uma falha na varredura de segurança interrompe todo o pipeline)
  7. 7

    Step 7: Estabeleça um fluxo completo de varredura de segurança

    Desenvolvimento:
    • Integração de plugins do Snyk/Trivy à IDE
    • Varredura manual após criar a imagem local

    Build:
    • Varredura automática no CI/CD
    • Falha imediata diante de vulnerabilidades CRITICAL para impedir o merge
    • Envio dos resultados ao Security Dashboard

    Repositório:
    • Segunda varredura no Harbor ou em outro registry de imagens
    • Política de vulnerabilidades para impedir o pull de imagens de alto risco

    Runtime:
    • Varredura periódica das imagens de produção (uma vez por semana)
    • Alerta ao encontrar novas vulnerabilidades

    Revisão periódica:
    • Revisão mensal das correções
    • Atualização das políticas e dos limites de vulnerabilidade

FAQ

Quais problemas de segurança uma imagem Docker pode ter?
Há quatro tipos de problemas de segurança:

1) Vulnerabilidades em pacotes do sistema operacional:
• Bibliotecas como OpenSSL, glibc e curl nas imagens base Alpine e Ubuntu
• Por exemplo, as vulnerabilidades graves do OpenSSL 3.0.x em 2022

2) Vulnerabilidades em dependências da aplicação:
• Falhas escondidas na árvore de dependências, como no caso do Log4j
• Muitos projetos Java nem sabiam que usavam Log4j

3) Configurações incorretas e vazamento de informações sensíveis:
• Senha do banco de dados escrita no Dockerfile
• Diretório .git deixado na imagem
• Contêiner executado como root

4) Riscos da cadeia de suprimentos:
• Imagens maliciosas no Docker Hub
• Uma pesquisa de 2018 encontrou imagens maliciosas criadas para enganar quem fazia pull sem verificar
Por que não se deve confiar cegamente nas imagens do Docker Hub? O número de 76% é correto?
Um relatório de pesquisa da NSFOCUS, publicado em março de 2018, mostrou que mais de três quartos (76%) das imagens selecionadas aleatoriamente no Docker Hub tinham vulnerabilidades conhecidas.

Embora o dado seja antigo, essas imagens antigas continuam em uso. Muitas imagens 'oficiais' também não são atualizadas em tempo real: a tag python:3.9 pode ter sido criada há seis meses e conter pacotes do sistema já desatualizados.

A qualidade das imagens do Docker Hub varia muito:
• Algumas são mantidas por desenvolvedores individuais e podem ficar seis meses sem atualização
• Algumas são chamadas de 'oficiais', mas foram apenas enviadas por uma empresa
• Não existe um padrão unificado de auditoria de segurança

Regra prática: sempre faça uma varredura na imagem baixada do Docker Hub antes de usá-la, mesmo quando ela tiver a tag 'oficial'.
Qual é a diferença entre Trivy e outras ferramentas de varredura, como Snyk, Clair e Anchore? Qual devo escolher?
Trivy:
• Ferramenta open source mais recomendada, gratuita, fácil de usar e com recursos suficientes
• Instalação simples (brew install trivy)
• Varredura rápida (cerca de 10 segundos na primeira execução e poucos segundos nas seguintes)
• Detecta vulnerabilidades, configurações incorretas e secrets vazados, além de verificar conformidade de licenças
• Já está integrado ao GitHub Actions e ao Harbor
• Leva 10 minutos para começar a usar e serve bem a equipes pequenas, médias e desenvolvedores individuais

Snyk:
• Produto comercial com recursos abrangentes
• Integração à IDE para alertas em tempo real
• Geração automática de PRs de correção
• A versão gratuita tem muitas limitações; é mais indicada para grandes empresas com orçamento

Clair:
• Mecanismo open source de varredura do registry Quay, com ampla possibilidade de personalização
• Configuração complexa e curva de aprendizado alta
• Mais indicado para equipes com engenheiros de segurança dedicados

Anchore:
• Solução empresarial com gerenciamento de políticas
• Indicada para setores com requisitos rigorosos de conformidade, como finanças e saúde

Recomendação: equipes pequenas e médias podem usar Trivy; grandes empresas podem avaliar o Snyk; equipes com engenheiros de segurança podem estudar o Clair.
Como interpretar os resultados do Trivy e no que devo prestar mais atenção?
Os resultados são classificados por gravidade:
• CRITICAL (corrija imediatamente; pode permitir o controle total do sistema)
• HIGH (corrija o quanto antes; pode ser explorada em um ataque)
• MEDIUM (correção recomendada; existe algum risco de segurança)
• LOW (prioridade menor; pode entrar no planejamento)

Dicas para ler o resultado:
1) Priorize vulnerabilidades que já têm uma versão corrigida (se Fixed Version mostrar none ou estiver vazio, ainda não há patch; resolva primeiro o que já tem correção)
2) Concentre-se em CRITICAL e HIGH (as CRITICAL exigem correção imediata e muitas vezes têm código de exploit público que pode ser usado diretamente)
3) Consulte os detalhes do CVE (procure o número em https://cve.mitre.org/ para entender o problema, o impacto e a dificuldade de exploração)
4) Entenda como o Trivy funciona (ele baixa um banco de vulnerabilidades em JSON e o compara à lista de pacotes da imagem; quando nome e versão correspondem a uma vulnerabilidade conhecida, gera um alerta, mas pode haver falsos positivos que exigem avaliação do código real)
Como corrigir sistematicamente as vulnerabilidades de uma imagem Docker?
Métodos de correção:
1) Escolha uma imagem base segura:
• Uma imagem Distroless tem apenas 3,06 MB, é menor que Alpine e não inclui shell nem gerenciador de pacotes, o que reduz ao mínimo a superfície de ataque
• As imagens Distroless do Google têm versões python3, nodejs e static
• As Docker Hardened Images de 2025 prometem quase zero CVEs e redução de até 95% no tamanho

2) Atualize a versão da imagem base:
• Use uma versão específica, como python:3.11.7, e não latest
• latest pode ficar meses sem atualização, deixando os pacotes do sistema obsoletos
• Verifique ativamente, uma vez por mês, se há uma versão secundária mais recente

3) Atualize os pacotes do sistema no Dockerfile:
• RUN apt-get update && apt-get upgrade -y && apt-get clean && rm -rf /var/lib/apt/lists/*
• Coloque update, upgrade e clean em uma única instrução RUN para reduzir o número de camadas

4) Atualize as dependências da aplicação:
• Altere requirements.txt e arquivos semelhantes
• Priorize uma atualização de patch: se Flask 2.0.1 tiver uma falha, tente primeiro a versão 2.0.x mais recente em vez de ir direto para 2.3.0
• Teste antes em um ambiente de homologação e só depois envie para produção

Boas práticas: use builds multi-stage, não execute como root, recrie as imagens regularmente (pelo menos uma vez por mês), use .dockerignore para evitar arquivos sensíveis e nunca use a tag latest.
Como integrar a varredura automática de segurança ao CI/CD?
Integração com GitHub Actions:
• Crie .github/workflows/docker-scan.yml
• Configure o disparo em push/pull_request
• Crie a imagem Docker e faça a varredura com aquasecurity/trivy-action
• Defina severity: 'CRITICAL,HIGH' e exit-code: '1' (o build falha ao encontrar vulnerabilidades graves)
• Envie os resultados à aba Security do GitHub

Integração com GitLab CI:
• Crie ou altere .gitlab-ci.yml
• Configure stages com build/test/security
• Use a imagem aquasec/trivy:latest no estágio security
• Execute trivy image --exit-code 1 --severity HIGH,CRITICAL
• Defina allow_failure: false (a falha da varredura interrompe todo o pipeline; em produção, deve ser false)

Registry Harbor:
• Integra Trivy e Clair desde a versão v1.2
• Pode fazer varredura automática após o push e varredura diária de todas as imagens
• Permite definir um limite de vulnerabilidades (por exemplo, impedir o pull de imagens com falhas CRITICAL)
• No ambiente de desenvolvimento, o push dispara a varredura e vulnerabilidades HIGH ou superiores adicionam a tag 'com vulnerabilidades'
• No ambiente de produção, um admission webhook do cluster K8s rejeita a implantação de imagens com essa tag
Como deve ser um fluxo completo de varredura de segurança de imagens Docker?
Fluxo completo:

Desenvolvimento:
• Integre plugins do Snyk ou Trivy à IDE para ver vulnerabilidades nas dependências enquanto programa
• Depois do build local, execute manualmente trivy image

Build:
• Use GitHub Actions/GitLab CI para verificar automaticamente cada nova imagem
• Interrompa imediatamente diante de uma vulnerabilidade CRITICAL e impeça o merge
• Envie o resultado ao Security Dashboard para acompanhar tendências

Repositório:
• Faça uma segunda varredura no Harbor ou em outro registry, porque o CI/CD pode deixar algo passar ou uma nova vulnerabilidade pode ser divulgada
• Defina políticas que impeçam o pull de imagens de alto risco

Runtime:
• Verifique semanalmente as imagens em execução na produção
• Ao encontrar uma nova vulnerabilidade, gere um alerta e planeje a correção

Revisão periódica:
• Revise mensalmente a situação das correções
• Atualize as políticas de varredura e os limites de vulnerabilidade

Depois de configurado, esse fluxo funciona de forma automática. Uma equipe pode levar aproximadamente um Sprint (duas semanas) da configuração à operação estável, em troca de proteção contínua.

21 min de leitura · Publicado em: 18 dez 2025 · Atualizado em: 4 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog