Como usar o Trivy no pipeline para bloquear imagens com CVEs críticas

1. Introdução ao Trivy e sua importância na segurança de containers

O Trivy é uma ferramenta open-source de varredura de vulnerabilidades desenvolvida pela Aqua Security. Ela detecta CVEs (Common Vulnerabilities and Exposures) em imagens de containers, sistemas de arquivos, repositórios Git e até mesmo em clusters Kubernetes. Sua principal vantagem é a simplicidade de uso combinada com um banco de dados atualizado constantemente.

Bloquear imagens que contenham CVEs críticas é uma prática essencial para organizações que precisam atender requisitos de compliance como PCI-DSS, SOC2 ou ISO 27001. Uma imagem vulnerável pode ser a porta de entrada para ataques como execução remota de código ou escalonamento de privilégios.

No ecossistema DevSecOps, o Trivy se destaca por ser gratuito, leve e fácil de integrar, diferentemente de ferramentas como Clair (mais complexa) ou Snyk (versão paga com recursos avançados). Ele se tornou o padrão para times que buscam segurança sem burocracia.

2. Instalação e configuração básica do Trivy

A instalação do Trivy pode ser feita de várias formas. Em ambientes CI/CD, as abordagens mais comuns são:

Usando Docker (recomendado para pipelines):

docker pull aquasec/trivy:latest

Instalação via script em um runner Linux:

curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh

Configuração de cache para acelerar scans repetitivos:

# Montar volume para cache do banco de dados
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  -v $HOME/.trivy:/root/.cache aquasec/trivy image --cache-dir /root/.cache minha-imagem:latest

Definição de thresholds por severidade:
- CRITICAL: vulnerabilidades que permitem execução remota de código sem autenticação
- HIGH: vulnerabilidades com impacto severo, mas que exigem condições específicas
- MEDIUM: riscos moderados que podem ser explorados em cenários limitados
- LOW: problemas menores, geralmente informativos

3. Integração do Trivy em pipelines CI/CD

Exemplo no GitHub Actions

Crie um workflow que executa o scan após o build da imagem:

name: Security Scan

on:
  push:
    branches: [ main ]

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

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

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'minha-app:${{ github.sha }}'
          format: 'table'
          exit-code: '1'
          severity: 'CRITICAL'

Exemplo no GitLab CI

Adicione um estágio de segurança que falha se encontrar CVEs críticas:

stages:
  - build
  - security

build:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

trivy-scan:
  stage: security
  script:
    - docker pull aquasec/trivy:latest
    - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock
        aquasec/trivy image --severity CRITICAL --exit-code 1
        $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  only:
    - main

Exemplo no Jenkins (Pipeline Declarativo)

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'docker build -t minha-app:${BUILD_NUMBER} .'
            }
        }
        stage('Security Scan') {
            steps {
                sh '''
                    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
                        aquasec/trivy image --severity CRITICAL --exit-code 1 \
                        minha-app:${BUILD_NUMBER}
                '''
            }
        }
    }
}

4. Estratégias de bloqueio e políticas de segurança

A política mais comum é interromper o pipeline imediatamente quando uma CVE crítica é encontrada. Para isso, use a combinação:

trivy image --severity CRITICAL --exit-code 1 minha-imagem:latest

Gerenciamento de exceções com .trivyignore:
Crie um arquivo na raiz do projeto para ignorar CVEs específicas que foram verificadas manualmente:

# .trivyignore
CVE-2023-1234  # Falso positivo confirmado pela equipe de segurança
CVE-2023-5678  # Não afeta nosso runtime (sistema operacional não utilizado)

Combinação com OPA/Gatekeeper:
Para políticas mais granulares, gere um relatório JSON e processe com OPA:

trivy image --format json --output report.json minha-imagem:latest
opa eval --data policy.rego --input report.json "data.security.deny"

5. Tratamento de falsos positivos e mitigação de vulnerabilidades

Nem toda CVE crítica afeta seu ambiente. Estratégias para lidar com isso:

  1. Verificar se a vulnerabilidade é explorável no seu contexto: uma CVE no kernel Linux pode não ser relevante se você usa uma imagem base Alpine minimalista.

  2. Rebuild de imagem base: atualize a imagem base (ex.: node:20-alpine para node:22-alpine) para resolver múltiplas CVEs de uma vez.

  3. Patch de dependências: atualize bibliotecas específicas no Dockerfile:

FROM node:20-alpine
RUN apk upgrade --no-cache libcrypto3 libssl3
  1. Uso de SBOM para rastreabilidade: o Trivy pode gerar um SBOM que ajuda a identificar exatamente qual pacote introduziu a vulnerabilidade:
trivy image --format cyclonedx --output sbom.json minha-imagem:latest

6. Monitoramento contínuo e relatórios de vulnerabilidades

Geração de relatórios HTML para auditoria:

trivy image --format template --template "@contrib/html.tpl" -o report.html minha-imagem:latest

Integração com Slack para alertas automáticos:

trivy image --severity CRITICAL --format json minha-imagem:latest | \
  jq '.Results[].Vulnerabilities[] | {CVEID: .VulnerabilityID, Severity: .Severity}' | \
  curl -X POST -H 'Content-type: application/json' \
  --data @- https://hooks.slack.com/services/SEU_TOKEN

Scans periódicos em produção (cron job):

# Executar toda segunda-feira às 6h
0 6 * * 1 trivy image --severity CRITICAL --exit-code 0 registry.example.com/app:latest > /var/log/trivy-scan.log

7. Melhores práticas e considerações finais

  • Versionamento do Trivy: mantenha o Trivy atualizado (use latest ou uma versão específica testada). Atualize o banco de dados com trivy image --download-db-only antes de scans.
  • Limitações: o Trivy depende de bancos públicos (NVD, Red Hat, Alpine). Imagens muito grandes (>2GB) podem demorar para escanear. Considere usar cache de camadas.
  • Checklist final para implementação segura:
  • [ ] Definir política de severidade mínima para bloqueio (CRITICAL ou HIGH)
  • [ ] Criar .trivyignore com exceções documentadas
  • [ ] Configurar notificações para times de segurança
  • [ ] Agendar scans recorrentes em imagens em produção
  • [ ] Revisar relatórios periodicamente para ajustar thresholds

Referências