Cadeia de suprimentos de software
Você revisa o seu código. Mas o que roda em produção inclui centenas de dependências, uma imagem base, ferramentas do build e o próprio runner do CI. Cada um desses pontos é uma forma de colocar código na sua produção sem passar por revisão nenhuma.
Os episódios conhecidos — pacote popular tomado por quem herdou a manutenção, atualização assinada de um fornecedor que distribuiu backdoor, dependência de build comprometida — têm o mesmo formato: o atacante não invadiu o alvo, ele entrou junto com uma atualização legítima. As práticas abaixo atacam esse formato.
SBOM: o inventário
Seção intitulada “SBOM: o inventário”Um SBOM (Software Bill of Materials) lista o que existe dentro do artefato. Ele não protege por si só — ele responde, em minutos, a pergunta que aparece quando sai uma CVE grave: “a gente usa isso? onde?”.
# gere durante o build, quando as versões já estão resolvidassyft registry.exemplo.com/loja:1.8.3 -o spdx-json > sbom.json# ou direto no build da imagemdocker buildx build --sbom=true --provenance=true -t registry.exemplo.com/loja:1.8.3 --push .
# no dia da CVE, a resposta sai do inventário, não de uma força-tarefagrep -i "log4j" sbom.jsonOs dois formatos usados na prática são SPDX e CycloneDX; qualquer ferramenta séria lê os dois. Guarde o SBOM junto do artefato, no registry como anexo, e não em um wiki que envelhece.
SLSA: níveis de garantia do build
Seção intitulada “SLSA: níveis de garantia do build”SLSA descreve o quanto se pode confiar em como o artefato foi produzido. O que muda de um nível para o outro, em linguagem prática:
- Nível 1 — o build é automatizado e gera procedência (metadados de como foi feito).
- Nível 2 — o build roda em serviço hospedado, e a procedência é assinada.
- Nível 3 — o build é isolado, as fontes de entrada são identificadas e ninguém consegue injetar passo ou variável fora do que está versionado.
Para a maior parte dos times, o alvo realista é o nível 2 com pipeline hospedado (GitHub Actions, GitLab CI) e assinatura via OIDC — sem chave de longa duração no CI.
Procedência e assinatura com Sigstore
Seção intitulada “Procedência e assinatura com Sigstore”Assinar responde “quem produziu isto”; a procedência responde “a partir de quê e como”. O Sigstore torna isso viável sem gerenciar chave privada: a identidade do workflow vira o assinante, com certificado de curta duração e registro público em log transparente.
# GitHub Actions — assinatura sem segredo armazenadopermissions: id-token: write # OIDC: a identidade vem daqui packages: write attestations: writesteps: - uses: sigstore/cosign-installer@v3 - run: cosign sign --yes registry.exemplo.com/loja@${{ steps.build.outputs.digest }} - run: | cosign attest --yes --predicate sbom.json --type spdxjson \ registry.exemplo.com/loja@${{ steps.build.outputs.digest }}Assine sempre pelo digest (@sha256:…), nunca pela tag. Tag é um ponteiro mutável:
assinar :1.8.3 garante pouco se alguém puder reapontá-la depois.
# verificação: quem assinou e a partir de qual workflowcosign verify registry.exemplo.com/loja@sha256:abc… \ --certificate-identity-regexp '^https://github.com/empresa/loja/\.github/workflows/.+' \ --certificate-oidc-issuer https://token.actions.githubusercontent.comA verificação só tem valor com as duas restrições de identidade. cosign verify sem
--certificate-identity aceita assinatura de qualquer pessoa do mundo — é o erro mais
comum na adoção.
Verificação na admissão
Seção intitulada “Verificação na admissão”Assinar sem verificar é teatro. A verificação precisa acontecer onde o artefato é usado:
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: { name: exigir-imagem-assinada }spec: validationFailureAction: Enforce # comece em Audit por algumas semanas rules: - name: verificar-assinatura match: { any: [{ resources: { kinds: [Pod], namespaces: [prod] } }] } verifyImages: - imageReferences: ["registry.exemplo.com/*"] attestors: - entries: - keyless: issuer: https://token.actions.githubusercontent.com subject: "https://github.com/empresa/*"Kyverno também substitui a tag pelo digest ao admitir o Pod, o que fecha a janela entre verificar e executar.
Higiene das entradas
Seção intitulada “Higiene das entradas”O resto do trabalho é reduzir o que entra sem revisão:
- Fixe versões com lockfile e commit dele; instale com
npm ci,pip install -rcom hashes,go.sumverificado. - Fixe também as actions do CI por commit SHA, não por tag móvel — o CI é código com acesso a segredos.
- Espelhe dependências em um registry interno (proxy), para não depender de um pacote público continuar existindo.
- Imagem base mínima e atualizada reduz a maior fatia de CVEs sem esforço de código.
- Revise atualização de dependência com a mesma atenção de código próprio; automatize a abertura do PR, não o merge.
Próximo passo: a credencial que o pipeline usa para publicar é o próximo alvo. Continue em Gestão de segredos.