Bei Sigstore vs. GPG geht es um die Wahl zwischen zwei Arten, Release-Artefakte, Container und Pakete zu signieren. Bei OpenPGP (GnuPG und kompatible Tools) bewahrt ein Maintainer einen langlebigen privaten Schlüssel auf, veröffentlicht dessen Fingerabdruck und liefert neben jeder Datei eine abgetrennte Signatur aus. Bei Sigstore authentifiziert sich der Signierer per OpenID Connect, und die Zertifizierungsstelle Fulcio stellt ein Zertifikat aus, das einen frischen Schlüssel für zehn Minuten an diese Identität bindet. Die Signatur wird im Transparenzlog Rekor erfasst, danach wird der Schlüssel verworfen. Verifizierer prüfen eine Identität, keinen Schlüssel.
Auf einen Blick
| Sigstore (keyless) | OpenPGP (GPG) | |
|---|---|---|
| Wem der Verifizierer vertraut | Einer OIDC-Identität (E-Mail-Adresse oder Workflow-URI) und ihrem Aussteller, abgesichert über die Root von Fulcio | Einem bestimmten öffentlichen Schlüssel, über einen separaten Kanal beschafft und geprüft |
| Lebensdauer des Signaturschlüssels | Ephemer; Zertifikat 10 Minuten gültig | Jahre; Ablauf vom Besitzer festgelegt und verlängert |
| Schlüsselmanagement | Für Signierer keines | Erzeugen, sichern, schützen, rotieren, widerrufen |
| Nachweis des Signaturzeitpunkts | Rekor-Logeintrag (und optional ein Zeitstempel nach RFC 3161) | Vom Signierer angegebener Erstellungszeitpunkt der Signatur |
| Transparenz | Jede Signatur wird öffentlich protokolliert | Keine |
| Widerruf | Bei ephemeren Schlüsseln nicht nötig; kompromittierte Identitäten werden über Richtlinien behandelt | Widerrufszertifikat, das der Besitzer veröffentlichen muss |
| Offline signieren | Nein (braucht Fulcio und Rekor, öffentlich oder privat) | Ja |
| Artefaktformat | Sigstore-Bundle (.sigstore.json): Zertifikat, Signatur oder DSSE-Envelope, Log-Nachweis | Datei .asc oder .sig |
| Typische Tools | cosign, sigstore-python, sigstore-js, gitsign, GitHub-Action attest-build-provenance | gpg, Sequoia (sq, sqv), Tools von rpm und apt |
| Wo es Standard ist | npm-Provenance (GA im September 2023), PyPI-Attestierungen (November 2024), Artefakt-Attestierungen von GitHub (GA im Juni 2024), CPython seit 3.11 (ab 3.14 die einzige Option), Kubernetes und viele Container-Images | Maven Central (Pflicht), Debian- und RPM-Repositorys, Tags des Linux-Kernels, viele Quell-Tarballs |
| Datenschutz | Identität des Signierers (E-Mail-Adresse oder Repository) ist im Log öffentlich | Schlüssel und User-ID nur öffentlich, wenn der Signierer sie veröffentlicht |
Was eine Keyless-Signatur enthält
npm speichert Sigstore-Bundles für Pakete, die mit Provenance veröffentlicht wurden. Das folgende Skript ruft die Attestierungen für @noble/curves 2.3.0 über die öffentliche Registry-API ab und dekodiert das Signaturzertifikat (20. Oktober 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
Das Paket trägt zwei Attestierungen: die eigene Publish-Attestierung von npm und ein in CI signiertes SLSA-Provenance-Statement. Das Zertifikat ist genau zehn Minuten gültig und wurde in der Sekunde seiner Ausstellung in Rekor protokolliert. Sein Subject ist weder eine Person noch ein Schlüssel, sondern der Workflow, der gelaufen ist – hier ein gemeinsam genutzter Release-Workflow in einem anderen Repository, gepinnt auf einen bestimmten Commit; weitere Fulcio-Erweiterungen halten Quell-Repository, Commit, Tag und Lauf fest. Der Sigstore-Bundle-Verifizierer und der npm-Provenance-Checker dekodieren dieselben Daten für jedes beliebige Paket.
Wie sich die Prüfung unterscheidet
Eine GPG-Signatur zu prüfen ist ein einziger Befehl, gpg --verify file.asc file, doch was das Ergebnis aussagt, hängt von allem ab, was davor geschieht: wie der Verifizierer an den Schlüssel gekommen ist, ob der Fingerabdruck mit einer vertrauenswürdigen Quelle abgeglichen wurde und ob der Schlüssel inzwischen widerrufen wurde. Die meisten Ergebnisse „Good signature“ in CI-Pipelines vertrauen schlicht dem Schlüssel, der ein paar Zeilen weiter oben importiert wurde.
Wer eine Sigstore-Signatur prüft, muss die erwartete Identität nennen – damit landet die Frage nach der Prüfrichtlinie direkt im Befehl. Das folgende Skript prüft die Prüfsummendatei aus dem Release v3.1.3 von cosign selbst dreimal mit dem offiziellen Container-Image von cosign v3.1.3: gegen die Identität, die das Sigstore-Projekt für seine Releases dokumentiert (ein Dienstkonto von Google, Aussteller https://accounts.google.com), gegen eine Workflow-Identität von GitHub Actions, die die Datei nicht signiert hat, und nachdem ein Byte an die Datei angehängt wurde.
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
Für das erste Ergebnis hat cosign die Zertifikatskette bis zur Sigstore-Root (verteilt über TUF) geprüft, außerdem die Signatur über die Datei, den Inclusion Proof von Rekor und ob die Log-Zeit in das Zehn-Minuten-Fenster des Zertifikats fällt. Der zweite Lauf zeigt, worum es beim Identitäts-Pinning geht: Die Signatur ist kryptografisch gültig, stammt aber nicht von der Identität, die der Verifizierer verlangt hat, und wird deshalb abgelehnt; der dritte Lauf scheitert an der Signatur selbst. Bei Artefakten, die in GitHub Actions gebaut werden, ist die Identität die Workflow-Datei samt Ref, etwa der Workflow release.yml@5320e209… im npm-Provenance-Zertifikat oben, und der Aussteller ist https://token.actions.githubusercontent.com.
Paket-Ökosysteme verpacken diese Prüfungen in eigene Tools. npm prüft sowohl seine Registry-Signaturen als auch die Sigstore-Attestierungen aller installierten Pakete:
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)
gh attestation verify erledigt dasselbe für Artefakt-Attestierungen von GitHub, und PyPI prüft Attestierungen beim Hochladen gegen den Trusted Publisher des Projekts.
Abwägungen, die du kennen solltest
- Das Vertrauen verlagert sich auf Identity Provider und die Infrastruktur von Sigstore: Ein Angreifer, der das GitHub-Konto des Maintainers oder den Release-Workflow unter seiner Kontrolle hat, kann gültige Signaturen erhalten. Transparenz macht das erkennbar (Maintainer können das Log auf ihre Identität hin überwachen), nicht unmöglich.
- Öffentliche Metadaten: Persönliche E-Mail-Identitäten erscheinen im öffentlichen Log; Workflow-Identitäten verraten Namen von Repositorys. Private Sigstore-Instanzen vermeiden beides.
- Verfügbarkeit: Zum Signieren müssen Fulcio und Rekor online sein. Die Prüfung eines Bundles funktioniert offline, sobald die Trust Root zwischengespeichert ist.
- Der Betrieb entwickelt sich weiter: Rekor v2, ein Tile-basiertes Log, ist seit Oktober 2025 allgemein verfügbar, doch die öffentliche Instanz nutzt weiterhin Rekor v1 als Standard, während die Maintainer an der Post-Quanten-Tauglichkeit arbeiten.
- Bei GPG liegen die Kosten beim Menschen: Schlüssel gehen verloren, laufen unbemerkt ab oder werden von Downstream-Nutzern nie geprüft – der Hauptgrund, warum sich Python, npm und PyPI davon abgewandt haben.
Wann welches Verfahren passt
- Pakete, die in GitHub Actions oder GitLab CI für npm, PyPI, crates oder Container gebaut werden: Sigstore über Trusted Publishing und Provenance.
- Container-Images: Signaturen und Attestierungen mit cosign, geprüft durch Admission Policies.
- Maven Central: OpenPGP ist Pflicht; füge zusätzlich ein Sigstore-Bundle hinzu, das Central seit Januar 2025 validiert.
- Pakete und Repositorys von Linux-Distributionen: OpenPGP, wie es die Tools der Distribution erwarten.
- Signieren in Air-Gap-Umgebungen oder offline: OpenPGP (oder eine private Sigstore-Instanz mit deinem eigenen Identity Provider).
- Git-Commits und -Tags: SSH- oder OpenPGP-Schlüssel oder gitsign für Keyless-Commits (siehe SSH vs. GPG für Commit-Signaturen).
Hinweise zur Migration
- In CI signieren, nicht auf Laptops: Verlagere Releases in einen Workflow mit OIDC-Token (
id-token: writein GitHub Actions) und signiere dort. - Für eine Übergangszeit beides veröffentlichen: Liefere Dateien
.ascund.sigstore.jsonaus und dokumentiere die erwartete Identität und den Aussteller neben dem alten Fingerabdruck des Schlüssels. - Registry-eigene Mechanismen nutzen, wo es sie gibt: npm
--provenanceund Trusted Publishing, Trusted Publishers bei PyPI, Artefakt-Attestierungen von GitHub. - Identitäten genau pinnen: Lege in Prüfrichtlinien Repository, Workflow-Datei und Tag oder Branch fest, nicht nur die Organisation.
- Das Log überwachen: Achte auf Einträge zu deinen Identitäten, und bewahre das Widerrufszertifikat deines OpenPGP-Schlüssels auf, bis das letzte damit signierte Release nicht mehr unterstützt wird.
Quellen
- Sigstore-Dokumentation: Prüfen mit cosign und Releases von cosign prüfen (Identität und Aussteller, die oben verwendet werden)
- cosign-Release v3.1.3
- Sigstore: Rekor v2 allgemein verfügbar und Weiterentwicklung von Rekor
- SLSA Provenance v1
- PEP 740, Index-Unterstützung für digitale Attestierungen und PEP 761, Abkündigung von PGP-Signaturen für CPython
- GitHub: Artefakt-Attestierungen allgemein verfügbar
- Sonatype: Central Publisher Portal validiert Sigstore-Signaturen
- RFC 9580, OpenPGP