Warum Autor-Metadaten allein nichts beweisen
Jeder kann git config user.name und user.email auf einen beliebigen Namen setzen und Commits im Namen eines Kollegen erstellen, ohne dass Git das verhindert. Dieser Artikel zeigt, wie GPG- und SSH-basierte Commit-Signaturen kryptographisch beweisen, wer einen Commit tatsächlich erstellt hat, wie man Schlüssel einrichtet, Signaturen verifiziert und signierte Commits über Branch-Protection-Regeln im Team erzwingt.
Inhaltsverzeichnis
- 1. Warum Autor-Metadaten keine Sicherheit bieten
- 2. Was eine Signatur kryptographisch tatsächlich beweist
- 3. GPG-Schlüssel erzeugen und für Git konfigurieren
- 4. Public Key exportieren und bei GitHub/GitLab hinterlegen
- 5. SSH-basierte Commit-Signierung als moderne Alternative
- 6. Signaturen lokal verifizieren mit git log und verify-commit
- 7. Der "Verified"-Badge: Nutzen und Grenzen
- 8. Signierte Commits über Branch-Protection-Regeln erzwingen
- 9. Key-Management: Ablauf, Revocation, Hardware-Token
- 10. Zusammenfassung
- 11. FAQ
1. Warum Autor-Metadaten keine Sicherheit bieten
Jeder Git-Commit enthält Autor-Metadaten wie Name und E-Mail, doch diese Felder werden ausschließlich clientseitig gesetzt, über git config user.name und git config user.email, ohne jede Prüfung durch Git selbst. Wer Schreibzugriff auf ein Repository hat oder auch nur lokal ein neues Repository klont, kann diese Werte auf einen beliebigen Namen setzen, etwa den eines Tech Leads oder Maintainers, und Commits erzeugen, die in jedem Log und jeder Weboberfläche wie von dieser Person stammend aussehen. Git unterscheidet an dieser Stelle nicht zwischen "echt" und "frei erfunden".
Genau das macht Commit-Spoofing zu einem trivialen Angriff, nicht zu einem theoretischen Randfall. Ein Angreifer mit Zugriff auf einen Fork, eine kompromittierte CI-Pipeline oder einen unsauber konfigurierten Merge-Workflow kann Commits im Namen eines vertrauenswürdigen Kollegen einschleusen, etwa um Reviewer zu täuschen oder schädlichen Code als bereits geprüft erscheinen zu lassen. Ohne kryptographische Signaturen bleibt jede Aussage über "wer hat das committet" reine Behauptung, keine überprüfbare Tatsache. Genau hier setzt Commit-Signierung mit GPG oder SSH an, denn sie bindet einen Commit an einen privaten Schlüssel, der im Gegensatz zu einem Namen nicht einfach kopiert werden kann.
2. Was eine Signatur kryptographisch tatsächlich beweist
Eine Signatur beweist nicht, dass eine bestimmte Person einen Commit erstellt hat, sondern etwas Präziseres: dass der Inhaber eines bestimmten privaten Schlüssels den exakten Commit-Objekt-Hash signiert hat. Git berechnet beim Signieren eine kryptographische Signatur über den vollständigen Commit-Inhalt, Tree-Hash, Parent-Hash, Autor, Committer und Message eingeschlossen, sodass jede nachträgliche Änderung an einem dieser Felder die Signatur ungültig macht. Diese Verknüpfung ist mathematisch, nicht sozial: Wer die Signatur prüft, verifiziert einen Schlüssel, keine Identität.
Die Verbindung zwischen Schlüssel und tatsächlicher Person entsteht erst durch ein zweites, separates Vertrauensmodell: bei GPG durch das Web of Trust oder eine zentrale Plattform wie GitHub, die einen hochgeladenen Public Key mit einem Account verknüpft, bei SSH-Signierung durch eine allowed_signers-Datei, die Schlüssel-Fingerprints expliziten E-Mail-Adressen zuordnet. Diese doppelte Struktur, kryptographischer Beweis auf der einen Seite, Schlüssel-zu-Identität-Zuordnung auf der anderen, ist entscheidend für das Verständnis, was eine Signatur leistet und was nicht: Sie beweist Schlüsselbesitz, nicht automatisch die Vertrauenswürdigkeit des Codes.
3. GPG-Schlüssel erzeugen und für Git konfigurieren
Der erste Schritt ist die Erzeugung eines dedizierten GPG-Schlüsselpaars mit gpg --full-generate-key. Empfehlenswert ist RSA mit mindestens 4096 Bit oder ein moderner Ed25519-Schlüssel, kombiniert mit einer sinnvollen Ablaufzeit von ein bis zwei Jahren statt "kein Ablauf". Die E-Mail-Adresse des Schlüssels muss exakt mit einer verifizierten E-Mail-Adresse des Git-Accounts übereinstimmen, sonst schlägt die spätere Verifikation durch GitHub oder GitLab fehl, selbst wenn die Signatur technisch korrekt ist.
Nach der Erzeugung liefert gpg --list-secret-keys --keyid-format=long die Key-ID, die in git config --global user.signingkey eingetragen wird. Mit git config --global commit.gpgsign true signiert Git anschließend jeden Commit automatisch, ohne dass -S manuell an jeden Befehl angehängt werden muss. Für Tags gilt dasselbe über git config --global tag.gpgSign true. Wer nur einzelne Commits signieren will, lässt commit.gpgsign auf false und nutzt gezielt git commit -S.
# Generate a dedicated GPG key pair for commit signing
$ gpg --full-generate-key
# Choose: (1) RSA and RSA, keysize 4096, expires in 1y
# List secret keys to get the key ID
$ gpg --list-secret-keys --keyid-format=long
sec rsa4096/3AA5C34371567BD2 2026-07-12 [SC] [expires: 2027-07-12]
uid Jane Doe <jane@mironsoft.de>
# Tell Git which key to use and enable signing by default
$ git config --global user.signingkey 3AA5C34371567BD2
$ git config --global commit.gpgsign true
$ git config --global tag.gpgSign true
# Sign an individual commit explicitly (if gpgsign is not global)
$ git commit -S -m "Add signed commit example"
4. Public Key exportieren und bei GitHub/GitLab hinterlegen
Der Public Key muss mit gpg --armor --export <key-id> im ASCII-armored Format exportiert und bei der jeweiligen Plattform hinterlegt werden, bei GitHub unter Settings, SSH and GPG keys, bei GitLab unter Preferences, GPG Keys. Erst ab diesem Moment kann die Plattform eingehende Signaturen gegen den hinterlegten Schlüssel prüfen und den "Verified"-Badge in der Weboberfläche anzeigen. Ohne hochgeladenen Public Key bleibt eine technisch valide Signatur für die Plattform unsichtbar und wird als unverifiziert dargestellt.
Wichtig ist, den privaten Schlüssel niemals zu teilen oder ungeschützt auf mehrere Maschinen zu kopieren, sondern stattdessen für jede Arbeitsumgebung einen eigenen Subkey zu erzeugen, der über den Hauptschlüssel widerrufen werden kann, ohne die gesamte Identität zu invalidieren. Ein Backup des privaten Schlüssels und vor allem des Revocation-Zertifikats gehört an einen Ort außerhalb des Arbeitsrechners, etwa einen verschlüsselten USB-Stick oder einen Passwort-Manager mit Dateianhang, da ein verlorener Schlüssel ohne Revocation-Zertifikat nicht mehr sauber zurückgezogen werden kann.
# ~/.gitconfig: signing configuration after key generation
[user]
name = Jane Doe
email = jane@mironsoft.de
signingkey = 3AA5C34371567BD2
[commit]
gpgsign = true
[tag]
gpgSign = true
[gpg]
program = gpg2
5. SSH-basierte Commit-Signierung als moderne Alternative
Seit Git 2.34 lässt sich Commit-Signierung auch komplett ohne GPG umsetzen, indem git config --global gpg.format ssh gesetzt und user.signingkey auf einen bereits vorhandenen SSH-Public-Key verweist, etwa ~/.ssh/id_ed25519.pub. Das ist für viele Teams die pragmatischere Wahl, weil ohnehin ein SSH-Schlüssel für den Repository-Zugriff existiert und kein separates GPG-Ökosystem mit eigenem Schlüsselformat, eigener Ablaufsteuerung und eigenem Web of Trust aufgebaut werden muss.
Für die lokale Verifikation benötigt Git eine allowed_signers-Datei, die Schlüssel-Fingerprints E-Mail-Adressen zuordnet, konfiguriert über gpg.ssh.allowedSignersFile. GitHub und GitLab pflegen ihre eigene Zuordnung serverseitig automatisch, sobald derselbe SSH-Public-Key bereits als Signing Key im Account hinterlegt ist, sodass für den "Verified"-Badge keine zusätzliche Konfiguration nötig ist. Lokal, etwa in CI-Pipelines, muss die allowed_signers-Datei jedoch explizit gepflegt werden, sonst schlägt die Verifikation trotz korrekter Signatur fehl.
# Use SSH keys instead of GPG for commit signing (Git >= 2.34)
$ git config --global gpg.format ssh
$ git config --global user.signingkey ~/.ssh/id_ed25519.pub
# Point Git at a local allowed_signers file for verification
$ git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
# allowed_signers file: maps email addresses to trusted SSH public keys
$ cat ~/.ssh/allowed_signers
jane@mironsoft.de ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGZ8k... jane-laptop
john@mironsoft.de ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3xy... john-yubikey
# Sign a commit with the configured SSH key
$ git commit -S -m "Switch to SSH-based commit signing"
6. Signaturen lokal verifizieren mit git log und verify-commit
git log --show-signature zeigt für jeden Commit direkt im Log, ob eine Signatur vorhanden und gültig ist, inklusive Key-ID und Vertrauensstatus. Für die gezielte Prüfung eines einzelnen Commits liefert git verify-commit <hash> eine kompakte Ja/Nein-Aussage mit Exit-Code, was sich hervorragend in Pre-Push-Hooks oder CI-Jobs einbauen lässt, um unsignierte oder ungültig signierte Commits vor dem Merge automatisiert abzulehnen.
Bei GPG-Signaturen zeigt die Ausgabe zusätzlich den Trust-Level des Schlüssels an, unbekannt, marginal oder vollständig vertrauenswürdig, abhängig davon, ob der Schlüssel lokal signiert oder importiert wurde. Bei SSH-Signaturen fällt dieser Trust-Layer weg, Git prüft ausschließlich, ob der Fingerprint in der allowed_signers-Datei zur angegebenen E-Mail-Adresse passt. Für Tags funktioniert dieselbe Logik über git verify-tag, was insbesondere bei Release-Tags in automatisierten Deployment-Pipelines sinnvoll ist, um sicherzustellen, dass nur signierte Releases ausgerollt werden.
# Show signature status directly in the log
$ git log --show-signature -1
commit 9f2a1c4e8b3d5f6a7c8e9b0d1f2a3b4c5d6e7f80
gpg: Signature made Sun Jul 12 10:14:22 2026 CEST
gpg: using RSA key 3AA5C34371567BD2
gpg: Good signature from "Jane Doe <jane@mironsoft.de>" [ultimate]
Author: Jane Doe <jane@mironsoft.de>
Date: Sun Jul 12 10:14:22 2026 +0200
Add signed commit example
# Verify a single commit and check the exit code (useful in CI)
$ git verify-commit 9f2a1c4
gpg: Good signature from "Jane Doe <jane@mironsoft.de>" [ultimate]
$ echo $?
0
# SSH signature verification looks slightly different
$ git log --show-signature -1
Good "git" signature for jane@mironsoft.de with ED25519 key SHA256:AbCdEf...
7. Der "Verified"-Badge: Nutzen und Grenzen
Der grüne "Verified"-Badge in GitHub oder GitLab bestätigt ausschließlich, dass die Signatur kryptographisch zu einem Public Key passt, der im Account des angezeigten Autors hinterlegt ist, und dass diese E-Mail-Adresse zum Zeitpunkt des Commits als verifiziert galt. Er bestätigt nicht, dass der Code korrekt, sicher oder frei von Schwachstellen ist, und auch nicht, dass die Person, die den Commit erstellt hat, tatsächlich autorisiert war, dies im Namen des Projekts zu tun.
Ein häufiges Missverständnis: Ein gestohlener, aber noch nicht widerrufener privater Schlüssel erzeugt weiterhin gültige, "Verified" markierte Signaturen, bis der zugehörige Public Key entfernt oder der Schlüssel per Revocation-Zertifikat für ungültig erklärt wird. Der Badge ist also ein Indikator für Schlüsselbesitz zum Signierzeitpunkt, kein Sicherheitssiegel für den Inhalt. Teams, die sich allein auf den Badge verlassen und Code-Reviews deshalb lockern, verschieben das eigentliche Sicherheitsproblem lediglich, statt es zu lösen.
8. Signierte Commits über Branch-Protection-Regeln erzwingen
Damit Signierung tatsächlich etwas bewirkt, statt eine optionale Nettigkeit einzelner Entwickler zu bleiben, muss sie über Branch-Protection-Regeln erzwungen werden. In GitHub aktiviert die Option "Require signed commits" unter den Branch Protection Rules eines geschützten Branches, dass Pushes mit unsignierten oder ungültig signierten Commits serverseitig abgelehnt werden, unabhängig davon, ob der lokale Entwickler commit.gpgsign vergessen hat oder bewusst umgehen wollte.
GitLab bietet dieselbe Durchsetzung über Push Rules unter "Reject unsigned commits" auf Projekt- oder Gruppenebene, zusätzlich lässt sich die Regel über eine Compliance-Pipeline oder einen Server-Side-Hook noch granularer steuern, etwa nur für bestimmte Branches oder nur für Merge-Commits. Wichtig für die Einführung im Team: Bestehende, unsignierte Historie bleibt davon unberührt, die Regel greift ausschließlich bei neuen Pushes, sodass ein rückwirkendes Umschreiben der Historie mit git filter-repo oder Rebase in der Regel nicht notwendig ist.
# .gitlab-ci.yml: reject unsigned commits as a CI gate
# (in addition to Settings > Repository > Push Rules > Reject unsigned commits)
stages:
- verify
verify-signed-commits:
stage: verify
image: alpine/git:latest
script:
# Fail the pipeline if any commit in this MR is not signed
- |
for sha in $(git log --pretty=%H origin/main..HEAD); do
git verify-commit "$sha" || { echo "Unsigned commit: $sha"; exit 1; }
done
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
9. Key-Management: Ablauf, Revocation, Hardware-Token
Ein GPG-Schlüssel ohne Ablaufdatum mag bequem erscheinen, ist aber ein Risiko: Geht der private Schlüssel verloren oder wird kompromittiert, bleibt er ohne aktives Handeln unbegrenzt gültig. Eine Ablaufzeit von ein bis zwei Jahren, die regelmäßig mit gpg --edit-key und expire verlängert wird, begrenzt den Schaden eines unbemerkten Verlusts automatisch. Das direkt nach der Schlüsselerzeugung erstellte Revocation-Zertifikat, gpg --output revoke.asc --gen-revoke <key-id>, muss getrennt vom Schlüssel selbst gesichert werden, denn es ist die einzige Möglichkeit, einen Schlüssel für ungültig zu erklären, wenn kein Zugriff mehr auf den privaten Schlüssel besteht.
Für produktive Teams empfiehlt sich ein Hardware-Token wie ein YubiKey, der den privaten Schlüssel direkt auf dem Gerät speichert und niemals als Datei auf der Festplatte exponiert. Jede Signatur erfordert dann eine physische Berührung des Tokens, was gestohlene Notebooks oder Malware auf dem Entwicklerrechner als Angriffsvektor für die Signierfunktion wirkungslos macht. Die folgende Tabelle vergleicht GPG-, SSH- und fehlende Signierung entlang der praktisch relevanten Kriterien.
| Kriterium | Ohne Signierung | GPG-Signierung | SSH-Signierung |
|---|---|---|---|
| Setup-Aufwand | Kein Aufwand, aber kein Schutz | Schlüsselerzeugung, Ablaufzeit, Web of Trust | Nutzt vorhandenen SSH-Key, minimaler Zusatzaufwand |
| Lokale Verifikation | Keine Prüfung möglich | git verify-commit mit Trust-Level | git verify-commit gegen allowed_signers |
| Plattform-Badge | Kein Verified-Badge | Verified-Badge nach Public-Key-Upload | Verified-Badge nach Signing-Key-Upload |
| Schlüsselverlust / Rotation | Kein Konzept nötig, aber auch kein Schutz | Revocation-Zertifikat und Ablaufdatum nötig | Einfach: neuen SSH-Key hinterlegen, alten entfernen |
| Hardware-Token-Support | Nicht relevant | YubiKey mit OpenPGP-Applet, etabliert | YubiKey als FIDO2/SSH Resident Key, wachsend |
Mironsoft
Git-Sicherheit, Commit-Signierung und CI/CD-Pipelines für PHP- und Magento-Teams
Commit-Signierung im Team sauber einführen?
Wir helfen Entwicklerteams, GPG- oder SSH-basierte Commit-Signierung einzurichten, Branch-Protection-Regeln zu konfigurieren und Key-Management-Prozesse zu etablieren, die auch bei Personalwechseln und Schlüsselverlust tragfähig bleiben.
Signing-Rollout
GPG- oder SSH-Signierung team- und CI-weit einrichten und dokumentieren
Branch-Protection-Audit
Bestehende Repository-Regeln prüfen und um Signaturzwang ergänzen
CI/CD-Integration
Verifikations-Gates in Pipelines aufsetzen, inklusive Release-Tag-Signierung
10. Zusammenfassung
Signierte Commits mit GPG oder SSH lösen ein konkretes Sicherheitsproblem: Autor-Metadaten wie git config user.name und user.email sind reine Behauptungen ohne jede kryptographische Absicherung und lassen sich von jedem beliebig setzen. Eine Signatur bindet einen Commit stattdessen an den Besitz eines privaten Schlüssels, verifizierbar mit git verify-commit oder git log --show-signature, und macht Commit-Spoofing damit technisch nachweisbar statt nur vermutbar.
Ob GPG oder die neuere SSH-basierte Signierung die bessere Wahl ist, hängt vom Team ab: GPG bietet ein etabliertes Ökosystem mit Web of Trust und breiter Hardware-Token-Unterstützung, SSH-Signierung punktet mit geringerem Einrichtungsaufwand, weil ohnehin vorhandene Schlüssel wiederverwendet werden. Entscheidend ist in beiden Fällen dieselbe Kette: Schlüssel generieren, Public Key bei der Plattform hinterlegen, Signierung über Branch-Protection-Regeln erzwingen und den privaten Schlüssel, im Idealfall auf einem Hardware-Token, konsequent schützen.
Signierte Commits mit GPG: Das Wichtigste auf einen Blick
Was Signaturen beweisen
Besitz eines privaten Schlüssels zum Zeitpunkt der Signierung, nicht automatisch Code-Qualität oder Autorisierung.
GPG-Setup
gpg --full-generate-key, user.signingkey, commit.gpgsign true, Public Key bei GitHub/GitLab hochladen.
SSH-Signierung
gpg.format ssh, vorhandenen SSH-Key als signingkey nutzen, allowed_signers-Datei lokal pflegen.
Durchsetzung & Schutz
Branch-Protection-Regeln erzwingen Signaturen serverseitig, Ablaufdaten, Revocation-Zertifikate und YubiKeys schützen den Schlüssel.