Sigstore vs GPG é a escolha entre duas formas de assinar artefatos de release, contêineres e pacotes. Com o OpenPGP (GnuPG e ferramentas compatíveis), o mantenedor guarda uma chave privada de longa duração, publica a impressão digital dela e distribui uma assinatura desanexada ao lado de cada arquivo. Com o Sigstore, o signatário se autentica via OpenID Connect, a autoridade certificadora Fulcio emite um certificado que vincula uma chave nova a essa identidade por dez minutos, a assinatura é registrada no log de transparência Rekor e a chave é descartada. Os verificadores conferem uma identidade, não uma chave.
Visão geral
| Sigstore (keyless) | OpenPGP (GPG) | |
|---|---|---|
| Em que o verificador confia | Uma identidade OIDC (e-mail ou URI do fluxo de trabalho) e o emissor, por meio da raiz do Fulcio | Uma chave pública específica, obtida e conferida fora de banda |
| Vida útil da chave de assinatura | Efêmera; certificado válido por 10 minutos | Anos; a expiração é definida e prorrogada pelo dono |
| Gestão de chaves | Nenhuma para os signatários | Gerar, fazer backup, proteger, rotacionar, revogar |
| Prova do momento da assinatura | Entrada no log do Rekor (e carimbo do tempo RFC 3161 opcional) | Hora de criação da assinatura declarada pelo signatário |
| Transparência | Toda assinatura é registrada publicamente | Nenhuma |
| Revogação | Desnecessária para chaves efêmeras; identidades comprometidas são tratadas por política | Certificado de revogação que o dono precisa publicar |
| Assinatura offline | Não (exige o Fulcio e o Rekor, públicos ou privados) | Sim |
| Formato do artefato | Bundle do Sigstore (.sigstore.json): certificado, assinatura ou envelope DSSE, prova do log | Arquivo .asc ou .sig |
| Ferramentas típicas | cosign, sigstore-python, sigstore-js, gitsign, attest-build-provenance do GitHub | gpg, Sequoia (sq, sqv), ferramentas do rpm e do apt |
| Onde é o padrão | Proveniência do npm (disponibilidade geral em setembro de 2023), atestados do PyPI (novembro de 2024), atestados de artefatos do GitHub (disponibilidade geral em junho de 2024), CPython desde a 3.11 (única opção a partir da 3.14), Kubernetes e muitas imagens de contêiner | Maven Central (obrigatório), repositórios Debian e RPM, tags do kernel Linux, muitos tarballs de código-fonte |
| Privacidade | A identidade do signatário (e-mail ou repositório) fica pública no log | Chave e ID de usuário públicos só se o signatário os publicar |
O que uma assinatura keyless contém
O npm armazena bundles do Sigstore dos pacotes publicados com proveniência. O script abaixo busca na API pública do registro os atestados de @noble/curves 2.3.0 e decodifica o certificado de assinatura (20 de outubro de 2026, curl, jq 1.8.1, OpenSSL 3.6.5).
#!/bin/sh
curl -s "https://registry.npmjs.org/-/npm/v1/attestations/@noble%2fcurves@2.3.0" -o att.json
jq -r '.attestations[].predicateType' att.json
bundle='.attestations[] | select(.predicateType == "https://slsa.dev/provenance/v1") | .bundle'
jq -r "$bundle | .mediaType" att.json
jq -r "$bundle | .verificationMaterial.tlogEntries[0] | \"Rekor log index \(.logIndex), integrated \(.integratedTime | tonumber | todate)\"" att.json
jq -r "$bundle | .verificationMaterial.certificate.rawBytes" att.json | openssl base64 -d -A > leaf.der
openssl x509 -inform DER -in leaf.der -noout -issuer -dates -ext subjectAltName
openssl x509 -inform DER -in leaf.der -noout -text | grep -A1 "57264.1.1:" | tail -1 | sed 's/^ */OIDC issuer: /'
rm -f att.json leaf.der
https://github.com/npm/attestation/tree/main/specs/publish/v0.1
https://slsa.dev/provenance/v1
application/vnd.dev.sigstore.bundle.v0.3+json
Rekor log index 2357213216, integrated 2026-08-06T07:37:48Z
issuer=O=sigstore.dev, CN=sigstore-intermediate
notBefore=Aug 6 07:37:48 2026 GMT
notAfter=Aug 6 07:47:48 2026 GMT
X509v3 Subject Alternative Name: critical
URI:https://github.com/paulmillr/jsbt/.github/workflows/release.yml@5320e209ca8cc9b1b0b569675e164bdd2a139d71
OIDC issuer: https://token.actions.githubusercontent.com
O pacote traz dois atestados: o atestado de publicação do próprio npm e uma declaração de proveniência SLSA assinada no CI. O certificado é válido por exatamente dez minutos e foi registrado no Rekor no mesmo segundo em que foi emitido. O titular dele não é uma pessoa nem uma chave, mas o fluxo de trabalho que foi executado — aqui, um fluxo de trabalho de release compartilhado, em outro repositório, fixado em um commit; outras extensões do Fulcio registram o repositório de origem, o commit, a tag e a execução. O verificador de bundles do Sigstore e o verificador de proveniência do npm decodificam os mesmos dados para qualquer pacote.
Como a verificação difere
Verificar uma assinatura GPG é um comando só, gpg --verify file.asc file, mas o significado dele depende de tudo o que veio antes: como o verificador obteve a chave, se a impressão digital foi conferida com uma fonte confiável e se a chave foi revogada desde então. A maioria dos resultados “Good signature” em pipelines de CI confia em qualquer chave que tenha sido importada algumas linhas antes.
Verificar uma assinatura do Sigstore exige nomear a identidade esperada, o que obriga a resolver a questão da política no próprio comando. O script abaixo verifica o arquivo de checksums da própria release v3.1.3 do cosign com a imagem de contêiner oficial do cosign v3.1.3, três vezes: com a identidade que o projeto Sigstore documenta para as releases dele (uma conta de serviço do Google, emissor https://accounts.google.com), com uma identidade de fluxo de trabalho do GitHub Actions que não assinou o arquivo e depois de acrescentar um byte ao arquivo.
url=https://github.com/sigstore/cosign/releases/download/v3.1.3
curl -sSLO "$url/cosign_checksums.txt"
curl -sSLO "$url/cosign_checksums.txt.sigstore.json"
cosign() { docker run --rm -v "$PWD":/work:ro -w /work ghcr.io/sigstore/cosign/cosign:v3.1.3 "$@"; }
echo "== expected identity"
cosign verify-blob cosign_checksums.txt \
--bundle cosign_checksums.txt.sigstore.json \
--certificate-identity keyless@projectsigstore.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com
echo "== any other identity"
cosign verify-blob cosign_checksums.txt \
--bundle cosign_checksums.txt.sigstore.json \
--certificate-identity "https://github.com/sigstore/cosign/.github/workflows/release.yml@refs/tags/v3.1.3" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
echo "== modified file"
printf 'x' >> cosign_checksums.txt
cosign verify-blob cosign_checksums.txt \
--bundle cosign_checksums.txt.sigstore.json \
--certificate-identity keyless@projectsigstore.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com
== expected identity
Verified OK
== any other identity
Error: failed to verify certificate identity: no matching CertificateIdentity found, last error: expected SAN value "https://github.com/sigstore/cosign/.github/workflows/release.yml@refs/tags/v3.1.3", got "keyless@projectsigstore.iam.gserviceaccount.com"
error during command execution: failed to verify certificate identity: no matching CertificateIdentity found, last error: expected SAN value "https://github.com/sigstore/cosign/.github/workflows/release.yml@refs/tags/v3.1.3", got "keyless@projectsigstore.iam.gserviceaccount.com"
== modified file
Error: failed to verify signature: could not verify message: invalid signature when validating ASN.1 encoded signature
error during command execution: failed to verify signature: could not verify message: invalid signature when validating ASN.1 encoded signature
No primeiro resultado, o cosign verificou a cadeia de certificados até a raiz do Sigstore (distribuída via TUF), a assinatura sobre o arquivo, a prova de inclusão do Rekor e se o horário do log cai dentro da janela de dez minutos do certificado. A segunda execução é a razão de ser da fixação de identidade: a assinatura é criptograficamente válida, mas não foi feita pela identidade que o verificador pediu, por isso é rejeitada; a terceira falha na própria assinatura. Para artefatos gerados no GitHub Actions, a identidade é o arquivo do fluxo de trabalho com a ref dele, como o fluxo de trabalho release.yml@5320e209… do certificado de proveniência do npm acima, e o emissor é https://token.actions.githubusercontent.com.
Os ecossistemas de pacotes embutem essas verificações nas próprias ferramentas. O npm verifica tanto as assinaturas do registro quanto os atestados do Sigstore de tudo o que está instalado:
cd "$(mktemp -d)" && npm init -y > /dev/null
npm install --ignore-scripts --no-fund --no-audit @noble/curves@2.3.0 @noble/hashes@2.3.0
npm audit signatures
added 2 packages in 589ms
audited 2 packages in 0s
2 packages have verified registry signatures
2 packages have verified attestations
(use --json --include-attestations to view attestation details)
O gh attestation verify faz o mesmo com os atestados de artefatos do GitHub, e o PyPI confere os atestados com o publicador confiável (trusted publisher) do projeto no momento em que eles são enviados.
Contrapartidas a considerar
- A confiança passa para os provedores de identidade e para a infraestrutura do Sigstore: um atacante que controle a conta do GitHub do mantenedor ou o fluxo de trabalho de release consegue obter assinaturas válidas. A transparência torna isso detectável (os mantenedores podem monitorar o log em busca da própria identidade), não impossível.
- Metadados públicos: identidades de e-mail pessoais aparecem no log público; identidades de fluxo de trabalho revelam nomes de repositórios. Implantações privadas do Sigstore evitam as duas coisas.
- Disponibilidade: assinar exige o Fulcio e o Rekor online. A verificação de um bundle funciona offline depois que a raiz de confiança está em cache.
- A operação evolui: o Rekor v2, um log baseado em tiles, está em disponibilidade geral desde outubro de 2025, mas a instância pública mantém o Rekor v1 como padrão enquanto os mantenedores trabalham na preparação para a criptografia pós-quântica.
- Os custos do GPG são humanos: chaves se perdem, expiram sem que ninguém perceba ou nunca são verificadas pelos usuários downstream — o principal motivo pelo qual Python, npm e PyPI deixaram de usá-lo.
Quando escolher cada um
- Pacotes gerados no GitHub Actions ou no GitLab CI para npm, PyPI, crates ou contêineres: Sigstore, via publicação confiável (trusted publishing) e proveniência.
- Imagens de contêiner: assinaturas e atestados do cosign, verificados por políticas de admissão.
- Maven Central: o OpenPGP é obrigatório; acrescente também um bundle do Sigstore, que o Central valida desde janeiro de 2025.
- Pacotes e repositórios de distribuições Linux: OpenPGP, como as ferramentas da distribuição esperam.
- Assinatura em ambiente isolado (air-gapped) ou offline: OpenPGP (ou uma implantação privada do Sigstore com seu próprio provedor de identidade).
- Commits e tags do Git: chaves SSH ou OpenPGP, ou o gitsign para commits keyless (veja SSH vs GPG para assinar commits).
Notas de migração
- Assine no CI, não em notebooks: mova as releases para um fluxo de trabalho com token OIDC (
id-token: writeno GitHub Actions) e assine lá. - Publique os dois durante um período de transição: distribua os arquivos
.asce.sigstore.jsone documente a identidade e o emissor esperados ao lado da impressão digital da chave antiga. - Use os mecanismos nativos do registro onde eles existirem: o
--provenancedo npm e a publicação confiável, os publicadores confiáveis do PyPI, os atestados de artefatos do GitHub. - Fixe as identidades com precisão nas políticas de verificação: repositório, arquivo do fluxo de trabalho e tag ou branch, não só a organização.
- Monitore o log em busca das suas identidades e guarde o certificado de revogação da sua chave OpenPGP até que a última release assinada com ela deixe de ter suporte.
Referências
- Documentação do Sigstore: verificação com o cosign e verificação das releases do cosign (a identidade e o emissor usados acima)
- Release v3.1.3 do cosign
- Sigstore: disponibilidade geral do Rekor v2 e a evolução do Rekor
- Proveniência SLSA v1
- PEP 740, suporte do índice a atestados digitais e PEP 761, descontinuação das assinaturas PGP do CPython
- GitHub: atestados de artefatos em disponibilidade geral
- Sonatype: o Central Publisher Portal valida assinaturas do Sigstore
- RFC 9580, OpenPGP