Como Garantir Proveniência Criptográfica de Contentores com Trivy, SBOM e Sigstore Cosign

Como Garantir Proveniência Criptográfica de Contentores com Trivy, SBOM e Sigstore Cosign

Fazer deploy de contentores Docker em produção confiando apenas em etiquetas de texto mutáveis (:latest ou :production) é um risco operacional grave: se um atacante comprometer uma credencial do teu registo de contentores, pode substituir a imagem legítima por uma versão envenenada sem alterar o nome da tag. Sem verificação criptográfica, o teu servidor descarrega e executa o código malicioso de olhos fechados.

Em setores como Fintech Startups (Neobanks) e Arqueologia e Património, garantir a proveniência imutável de cada componente é um requisito técnico e de conformidade indispensável.

Na infraestrutura de CI/CD que operamos no Webxtek Studio, aplicamos uma validação tripla antes de qualquer imagem tocar num servidor Linux: inspeção de vulnerabilidades com Trivy, geração do inventário de componentes SBOM CycloneDX e assinatura imutável do digest SHA-256 via Sigstore Cosign com OIDC, sem recorrer a chaves estáticas no disco.

Esta segurança na cadeia de fornecimento alinha-se diretamente com o perímetro defensivo do nosso Alerta CISA, NSA e FBI: Blindagem PHP, Node e Portas Expostas.

Abaixo explico como integrar esta esteira de validação criptográfica no teu pipeline de CI/CD.


1. Do Rótulo Falsificado ao Digest Imutável: Trivy, SBOM CycloneDX e Sigstore Cosign

Para garantires a proveniência criptográfica dos teus contentores em produção, tens de substituir tags mutáveis por digests SHA-256 imutáveis, bloquear builds vulneráveis com o scanner Trivy, anexar um inventário SBOM CycloneDX e assinar a imagem via OIDC com o Sigstore Cosign antes de a validar no servidor de destino.

Para perceberes porque é que o comando docker pull minhaempresa/api:latest é uma roleta russa operacional, precisamos de olhar para a arquitetura dos registos de contentores compatíveis com a norma OCI (Open Container Initiative). Uma tag como :latest ou :v2.1.0 não é a imagem em si; é apenas um apontador mutável que hoje aponta para o resumo criptográfico sha256:4f8a... e amanhã pode ser reescrito por qualquer pessoa com acesso de escrita no registo para apontar para sha256:999b....

O perigo de confiar cegamente em dependências de terceiros sem um inventário auditado ficou dolorosamente demonstrado no Ataque Supply Chain ao LiteLLM: GhostAction e Fuga de Tokens, onde um pipeline de CI/CD foi sequestrado para roubar credenciais cloud através de dependências comprometidas.

Para transformar uma pipeline frágil numa cadeia de fornecimento inviolável, alinhada com a documentação oficial do Sigstore Cosign e com as especificações do scanner Aqua Security Trivy, ligamos três mecanismos determinísticos no pipeline de CI/CD:

Fluxo de Proveniencia Criptografica de Contentores (Padrao Webxtek Studio):

1. Compilacao Deterministica:
   O Docker constroi a imagem multi-stage e exporta o Digest Imutavel (@sha256:4f8a...).

2. Portao de Seguranca (Trivy):
   O Trivy analisa pacotes Debian/Alpine e lockfiles (npm/pip/composer).
   - Se encontrar 1 CVE CRITICAL ou HIGH com correcao disponivel -> Quebra o pipeline na hora (Exit Code 1).

3. Inventario de Ingredientes (SBOM):
   O Trivy gera o ficheiro sbom.cdx.json (norma CycloneDX).

4. Assinatura Keyless (Cosign + OIDC):
   - O runner do GitHub Actions pede um token JWT OIDC.
   - A CA Fulcio emite um certificado X.509 efemero (valido por 10 minutos) amarrado ao commit e workflow exatos.
   - O Cosign assina a imagem e anexa o SBOM assinado no registo OCI, gravando a prova no livro-razao Rekor.

5. Alfandega no Servidor Linux:
   Antes de correr 'docker compose up', o servidor executa 'cosign verify'.
   - Se a assinatura nao pertencer ao nosso repositorio GitHub oficial -> Bloqueia o arranque e dispara alerta!

A Brilhante Engenharia do Keyless Signing (Assinatura Sem Chaves Estáticas)

No passado, quando tentavas implementar assinatura de imagens (como o antigo Docker Content Trust / Notary v1), tinhas um problema grave de gestão de segredos: precisavas de gerar uma chave privada criptográfica, guardá-la nos segredos do CI/CD e protegê-la durante anos. Se alguém roubasse essa chave privada dos segredos do GitHub, podia assinar malware em teu nome!

O Sigstore Cosign eliminou as chaves privadas permanentes através da criptografia efémera baseada em identidade OIDC:

  1. Quando o teu workflow corre no GitHub Actions (ou GitLab CI), o Cosign não usa nenhuma chave guardada no disco. Ele gera um par de chaves temporário exclusivamente na memória RAM daquele job.
  2. O Cosign apresenta o token OIDC do GitHub à autoridade de certificação gratuita Fulcio (gerida pela Linux Foundation).
  3. O Fulcio confirma matematicamente que aquele pedido veio mesmo do repositório github.com/tua-empresa/tua-api na branch main, e emite um certificado digital válido por apenas 10 minutos.
  4. O Cosign assina o hash @sha256:... da imagem, grava o carimbo de tempo no registo de transparência pública Rekor (funciona exatamente como o Certificate Transparency dos browsers) e apaga a chave privada da memória RAM. Passados 10 minutos, a chave já nem existe, mas qualquer servidor no mundo pode verificar através do registo Rekor que a assinatura era válida no momento exato em que o certificado estava ativo!

2. Pipeline Completo de Produção no GitHub Actions: Scan, SBOM e Assinatura OIDC

No meu dia a dia em produção, não confio em verificações manuais. Aqui tens o manifesto completo de GitHub Actions (.github/workflows/container-supply-chain.yml) que utilizamos para compilar, auditar com Trivy, gerar o SBOM CycloneDX e assinar quer a imagem quer o atestado SBOM sem uma única chave privada estática:

# ============================================================================
# .github/workflows/container-supply-chain.yml
# Pipeline Blindado: Build + Trivy Gate + SBOM CycloneDX + Sigstore Cosign OIDC
# ============================================================================

name: Build, SBOM e Assinatura Criptografica OCI

on:
  push:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

# Permissoes estritas Zero-Trust (id-token: write e obrigatorio para o Sigstore Cosign OIDC)
permissions:
  contents: read
  packages: write
  id-token: write

jobs:
  build_scan_and_sign:
    runs-on: ubuntu-24.04
    timeout-minutes: 15
    steps:
      - name: 1. Checkout Imutavel do Codigo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false

      - name: 2. Instalar Cosign (Sigstore)
        uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0

      - name: 3. Autenticar no GitHub Container Registry (GHCR)
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: 4. Compilar e Publicar Imagem por Digest Imutavel
        id: build_image
        uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }}

      - name: 5. Portao de Seguranca Trivy (Bloquear CVEs CRITICAL e HIGH com Patch)
        uses: aquasecurity/trivy-action@18f2510ee396bbf4004029bd2b394f2dd8c87dbb # 0.28.0
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build_image.outputs.digest }}
          format: 'table'
          exit-code: '1'
          ignore-unfixed: true
          vuln-type: 'os,library'
          severity: 'CRITICAL,HIGH'

      - name: 6. Gerar Inventario SBOM em Formato CycloneDX (JSON)
        uses: aquasecurity/trivy-action@18f2510ee396bbf4004029bd2b394f2dd8c87dbb # 0.28.0
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build_image.outputs.digest }}
          format: 'cyclonedx'
          output: 'sbom.cdx.json'

      - name: 7. Assinar Criptograficamente o Digest da Imagem com Cosign (Keyless OIDC)
        run: |
          cosign sign --yes \
            "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build_image.outputs.digest }}"

      - name: 8. Anexar e Assinar o Atestado SBOM CycloneDX no Registo OCI
        run: |
          cosign attest --yes \
            --predicate sbom.cdx.json \
            --type cyclonedx \
            "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build_image.outputs.digest }}"

Analisa o que este pipeline garante matematicamente antes de qualquer deploy:

  • No Passo 5, se uma biblioteca Python, Node.js, PHP ou um pacote base Debian tiver uma vulnerabilidade HIGH ou CRITICAL com correção disponível, o Trivy devolve exit-code: 1, interrompe a execução imediatamente e a imagem nunca chega a ser assinada no Passo 7!
  • No Passo 7 e Passo 8, o Cosign nunca assina a tag mutável :sha-...; assina exclusivamente o resumo criptográfico @sha256:... (steps.build_image.outputs.digest) e anexa o ficheiro sbom.cdx.json assinado como uma camada de atestado OCI in-toto diretamente no registo.

3. O Portão de Admissão no Servidor de Produção Linux: Validar Antes de Executar

Assinar imagens no CI/CD só serve de alguma coisa se o teu servidor de produção se recusar terminantemente a arrancar imagens que não tenham uma assinatura válida.

Se operas clusters Kubernetes (EKS, GKE ou K3s), podes impor esta regra usando o admission controller Kyverno ou o Sigstore Policy Controller. Mas se operas servidores Linux dedicados ou VPS com Docker Compose (um cenário muito frequente em arquiteturas enxutas de alta velocidade), nunca deves correr docker compose up -d diretamente.

Cria este wrapper de verificação criptográfica (/usr/local/bin/webxtek-verified-deploy.sh) no teu servidor de produção Debian/Ubuntu:

#!/usr/bin/env bash
# ============================================================================
# /usr/local/bin/webxtek-verified-deploy.sh
# Alfandega Criptografica de Producao: Valida Assinatura Cosign e SBOM antes do Deploy
# ============================================================================

set -euo pipefail

# 1. Definir a imagem obrigatoriamente pelo seu Digest SHA-256 imutavel
IMAGE_DIGEST="${1:?Erro: Indica a imagem com @sha256:...}"
EXPECTED_REPO="https://github.com/tua-organizacao/teu-repositorio/.github/workflows/container-supply-chain.yml@refs/heads/main"
OIDC_ISSUER="https://token.actions.githubusercontent.com"

echo "[1/3] A verificar assinatura criptografica Keyless no registo Rekor..."
cosign verify \
  --certificate-identity="$EXPECTED_REPO" \
  --certificate-oidc-issuer="$OIDC_ISSUER" \
  "$IMAGE_DIGEST" > /dev/null

echo "[OK] Assinatura de imagem confirmada matematicamente!"

echo "[2/3] A validar presenca e assinatura do atestado SBOM CycloneDX..."
cosign verify-attestation \
  --type cyclonedx \
  --certificate-identity="$EXPECTED_REPO" \
  --certificate-oidc-issuer="$OIDC_ISSUER" \
  "$IMAGE_DIGEST" | jq -r '.payload' | base64 -d | jq '.predicate.metadata.component.name'

echo "[OK] Inventario SBOM CycloneDX integro e verificado!"

echo "[3/3] A iniciar contentor blindado em producao..."
export VERIFIED_IMAGE="$IMAGE_DIGEST"
docker compose -f /opt/app/docker-compose.prod.yml up -d --pull always --no-build

Faz um teste prático: se um atacante conseguir invadir o teu registo de contentores, compilar uma imagem maliciosa no computador dele e empurrá-la para o teu repositório, quando o teu servidor correr /usr/local/bin/webxtek-verified-deploy.sh, o comando cosign verify falha no primeiro segundo com Error: no matching signatures found e o contentor adulterado nunca chega a ser iniciado!


4. Comparativo de Engenharia: Deploy Tradicional vs. Cadeia Blindada (Trivy + SBOM + Cosign)

Na tabela abaixo comparo o fluxo de deploy tradicional usado pela maioria das equipas com o pipeline de proveniência criptográfica que implementamos no Webxtek Studio:

Dimensão Operacional / Segurança Pipeline Docker Tradicional (docker pull :latest) Padrão Blindado Webxtek (Trivy + SBOM + Cosign OIDC) Impacto Real na Tua Operação
Referência da Imagem em Produção Tag mutável (:latest, :prod, :v1.4) Digest criptográfico imutável (@sha256:4f8a...) Imunidade total contra ataques de substituição de tags (Tag Tampering)
Segredos de Assinatura no CI/CD Inexistentes ou chaves privadas estáticas em risco de roubo Zero chaves estáticas (Assinatura efémera via OIDC + Fulcio + Rekor) Elimina o risco de roubo da chave privada de assinatura
Deteção de Pacotes Vulneráveis Reativa (só descobres após um incidente ou pentest) Preventiva no build (trivy --exit-code 1 bloqueia CVEs críticas) Código vulnerável é travado antes de chegar ao registo OCI
Resposta a Novos Zero-Days (SBOM) Lenta (exige entrar por SSH em cada servidor para ver versões) Instantânea (consulta ao atestado JSON CycloneDX assinado) Auditoria de impacto em segundos em toda a frota
Conformidade Legal (CRA / DORA / NIS2) Incumprimento por falta de inventário e proveniência 100% Auditável com trilho criptográfico público no Rekor Preparação nativa para o EU Cyber Resilience Act

Quando lideras uma operação em Fintech Startups (Neobanks) ou geres plataformas digitais onde a integridade histórica e documental é sagrada, como em Arqueologia e Património, alinhar a tua infraestrutura através de Consultoria Técnica Antes de Construir protege o ativo mais valioso da tua empresa: a confiança. E quando essa solidez técnica é acompanhada por um posicionamento claro de mercado, apoiado em Rebranding e Evolução de Marca e numa estratégia consistente de Conteúdo SEO Mensal e Autoridade, transformas a tua maturidade de engenharia num argumento comercial decisivo perante clientes institucionais.


5. Checklist Prática de 5 Passos Para Produção

Segue estes cinco passos técnicos para implementares a assinatura e verificação de contentores na tua operação ainda esta semana:

  1. Migra para Imagens Base Minimalistas ou Distroless: Quanto mais pacotes desnecessários tiver a tua imagem Docker (como editores de texto, compiladores ou shells em imagens ubuntu:latest completas), mais alertas o Trivy vai disparar. Usa builds multi-stage e imagens finais distroless ou alpine enxutas para reduzir a superfície de ataque em 80%.
  2. Ativa o Bloqueio do Trivy com –ignore-unfixed: Configura o passo do Trivy no teu pipeline com --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed segundo a documentação de trivy.dev, garantindo que a equipa só é bloqueada quando já existe uma atualização de segurança oficial disponível para corrigir a falha.
  3. Exige id-token: write e Assinatura Keyless: Implementa o cosign sign e cosign attest nos teus workflows seguindo o guia oficial de docs.sigstore.dev, eliminando qualquer chave privada manual dos segredos do teu repositório.
  4. Arquiva e Indexa os Ficheiros sbom.cdx.json: Além de anexares o SBOM à imagem no registo OCI, envia automaticamente o ficheiro CycloneDX gerado em cada release para uma plataforma de monitorização contínua (como o OWASP Dependency-Track) para receberes alertas imediatos se surgir um CVE novo num pacote antigo.
  5. Força a Verificação Antes do Arranque (cosign verify): Nunca deixes um nó de produção executar uma imagem sem validar primeiro os parâmetros --certificate-identity e --certificate-oidc-issuer. Para além dos scanners de vulnerabilidades estáticas de pacotes, a auditoria semântica do próprio código aplicacional pode ser acelerada através da nossa arquitetura de agentes Caçador e Verificador com sandboxing.

Construir pipelines de software resilientes exige tratar cada artefacto compilado com o rigor de um contrato criptográfico assinado. No Webxtek Studio, desenhamos arquiteturas de entrega contínua e sistemas de produção preparados para as normas europeias mais exigentes. Através de Consultoria Técnica Antes de Construir, projetos estratégicos de Rebranding e Evolução de Marca e programas de Conteúdo SEO Mensal e Autoridade, ajudamos a tua empresa a consolidar uma infraestrutura inviolável e uma autoridade técnica inquestionável no teu mercado.

[+] [ INDEX_DIRECTORY ] 14 tópicos ▼
[ SYSTEM.FAQ ]

Perguntas Frequentes

Porque é que fazer deploy de imagens Docker por tags mutáveis (:latest ou :v1.2) sem verificar a assinatura criptográfica é um risco crítico?

Porque uma tag num registo de contentores (Docker Hub, GHCR ou AWS ECR) é apenas um ponteiro de texto mutável. Se um atacante comprometer uma credencial do registo, pode substituir a imagem associada à tag :latest por uma versão contendo malware sem alterar o nome. Ao exigires o resumo criptográfico imutável (@sha256:...) assinado com Sigstore Cosign, o servidor recusa executar qualquer byte que não tenha sido gerado pela tua pipeline oficial.

Como funciona a assinatura Keyless (sem chaves estáticas) do Sigstore Cosign com Fulcio e Rekor no GitHub Actions?

Em vez de guardares uma chave privada estática nos segredos do CI (que poderia ser roubada), o Cosign solicita um token de identidade OpenID Connect (OIDC) de curta duração ao runner do GitHub Actions. A autoridade de certificação Fulcio valida esse token e emite um certificado X.509 efémero válido apenas por 10 minutos para assinar o digest da imagem, gravando a prova criptográfica no livro-razão público e imutável Rekor antes de destruir a chave da memória.

Para que serve um atestado SBOM em formato CycloneDX anexado à imagem e como responde ao EU Cyber Resilience Act (CRA)?

O Software Bill of Materials (SBOM) em formato CycloneDX é a lista exata de todos os pacotes de sistema operativo (Debian/Alpine) e bibliotecas de linguagem (npm, pip, composer, cargo) compilados dentro da imagem. Ao anexares o SBOM como um atestado assinado (cosign attest), consegues identificar em segundos se uma nova vulnerabilidade zero-day afeta os teus contentores em produção e cumpres os requisitos legais de rastreabilidade do Cyber Resilience Act europeu.

Como travas automaticamente no pipeline CI vulnerabilidades críticas sem bloquear a equipa por falhas sem correção disponível?

Ao executares o scanner Trivy com as flags --exit-code 1 --severity CRITICAL,HIGH --ignore-unfixed --vuln-type os,library, o pipeline quebra imediatamente o build se existir uma vulnerabilidade grave que já tenha patch oficial lançado pelos mantenedores, forçando a atualização do pacote antes da imagem ser assinada.

> INICIAR_PROJETO

Precisa de um website que transmita confiança, apareça na pesquisa e dê mais força à sua presença digital? Comece a conversa aqui.