Assinar imagens e exigir assinatura no cluster
Assinar imagem responde a uma pergunta específica: este artefato foi produzido pelo nosso pipeline, a partir do nosso repositório? Sem verificação no cluster, a assinatura é decorativa — este guia faz as duas pontas.
1. Assine sem gerenciar chave
Seção intitulada “1. Assine sem gerenciar chave”O modo keyless do Sigstore usa a identidade do workflow (via OIDC) para emitir um certificado de curta duração e registrar a assinatura em log público de transparência. Não há chave privada para guardar, rotacionar ou vazar.
name: publicaron: push: { branches: [main] }
permissions: id-token: write # necessário para o keyless packages: write contents: read
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - id: build uses: docker/build-push-action@v6 with: push: true tags: registry.exemplo.com/loja:${{ github.sha }}
- uses: sigstore/cosign-installer@v3 - name: Assinar pelo digest run: | cosign sign --yes \ registry.exemplo.com/loja@${{ steps.build.outputs.digest }}Assine sempre o digest, nunca a tag. Tag é ponteiro mutável: assinar :1.8.3 garante
pouco se alguém puder reapontá-la depois.
2. Publique também a proveniência e o SBOM
Seção intitulada “2. Publique também a proveniência e o SBOM”Assinatura diz quem; atestação diz a partir de quê.
syft registry.exemplo.com/loja@sha256:SUBSTITUA -o spdx-json > sbom.jsoncosign attest --yes --predicate sbom.json --type spdxjson \ registry.exemplo.com/loja@sha256:SUBSTITUAAssinatura, SBOM e proveniência ficam no próprio registry, ao lado da imagem — é isso que permite responder a uma CVE nova em minutos.
3. Verifique no pipeline antes de promover
Seção intitulada “3. Verifique no pipeline antes de promover”cosign verify registry.exemplo.com/loja@sha256:SUBSTITUA \ --certificate-identity-regexp '^https://github.com/empresa/loja/\.github/workflows/.+' \ --certificate-oidc-issuer https://token.actions.githubusercontent.comAs duas restrições de identidade não são opcionais: cosign verify sem
--certificate-identity aceita assinatura de qualquer pessoa do mundo — é o erro mais
comum na adoção, e ele anula todo o resto.
4. Exija assinatura na admissão
Seção intitulada “4. Exija assinatura na admissão”apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: { name: exigir-imagem-assinada }spec: validationFailureAction: Audit # comece aqui; Enforce vem no passo 5 background: false webhookTimeoutSeconds: 30 rules: - name: verificar-assinatura match: any: [{ resources: { kinds: [Pod], namespaces: [prod, hom] } }] verifyImages: - imageReferences: ["registry.exemplo.com/*"] mutateDigest: true # troca tag por digest ao admitir verifyDigest: true required: true attestors: - entries: - keyless: issuer: https://token.actions.githubusercontent.com subject: "https://github.com/empresa/*" rekor: { url: https://rekor.sigstore.dev }mutateDigest: true fecha a janela entre verificar e executar: o Pod passa a referenciar o
digest verificado, e não a tag.
A alternativa ao Kyverno é o policy-controller do Sigstore; a mecânica é a mesma.
5. Modo auditoria antes de bloquear
Seção intitulada “5. Modo auditoria antes de bloquear”kubectl get policyreport -A | grep -i exigir-imagem-assinadakubectl get clusterpolicyreport -o wideRode em Audit por uma a duas semanas e resolva o que aparecer. Você vai encontrar imagens
legítimas não assinadas: agentes de observabilidade, controladores instalados por Helm,
jobs antigos. Para cada uma, decida entre assinar (se for sua), confiar no fornecedor com
regra específica, ou registrar exceção com prazo.
# exceção com dono e prazo — nunca uma exceção permanente e silenciosaapiVersion: kyverno.io/v2kind: PolicyExceptionmetadata: { name: agentes-terceiros, namespace: observabilidade }spec: exceptions: - policyName: exigir-imagem-assinada ruleNames: [verificar-assinatura] match: any: [{ resources: { namespaces: [observabilidade] } }] # Dono @ana — revisão em 2026-12-01, quando o fornecedor passar a assinarSó depois disso troque para validationFailureAction: Enforce, e comece por um namespace.
Se der errado
Seção intitulada “Se der errado”| Sintoma | Causa provável |
|---|---|
no matching signatures |
Assinou a tag e verifica o digest (ou o contrário) |
| Verificação passa para qualquer imagem | Faltou --certificate-identity-regexp |
Pods param de subir ao ligar Enforce |
Imagens de terceiros não assinadas — volte para Audit |
| Timeout no webhook | Verificação lenta contra o Rekor; ajuste webhookTimeoutSeconds e cache |
| Falha só em ambiente sem internet | Keyless precisa alcançar Fulcio/Rekor — considere chave própria ou espelho |
Em ambiente isolado, o caminho é chave gerenciada em KMS (cosign sign --key awskms://...)
com verificação pela chave pública.
Checklist de pronto
Seção intitulada “Checklist de pronto”- Pipeline assinando pelo digest, sem chave estática.
- SBOM e proveniência publicados como atestações.
- Verificação no pipeline com identidade e emissor restritos.
- Política de admissão instalada em modo auditoria.
- Relatórios revisados e acervo tratado.
-
Enforceligado por namespace, com exceções datadas. - Alerta quando uma imagem sem assinatura é recusada.