SSH vs GPG pour signer les commits, c’est le choix de la clé qu’utilise Git lorsque vous exécutez git commit -S ou git tag -s. Avec OpenPGP (le choix par défaut, généralement GnuPG), Git stocke une signature OpenPGP dans l’en-tête gpgsig du commit. Avec SSH (gpg.format=ssh, Git 2.34 et versions ultérieures), Git appelle ssh-keygen -Y sign et stocke une signature SSHSIG au même endroit. Dans les deux cas, la signature couvre l’objet commit, qui désigne l’arbre, les parents, l’auteur et le message : une seule signature authentifie donc tout l’historique jusqu’à ce commit.
Vue d’ensemble
| Signature SSH | Signature OpenPGP (GPG) | |
|---|---|---|
| Prise en charge par Git | Git 2.34 (novembre 2021), gpg.format=ssh | git commit -S depuis Git 1.7.9 (2012) ; tags signés bien avant |
| Outil de signature | ssh-keygen -Y sign, OpenSSH 8.1 ou ultérieur (éviter la 8.7) | gpg ou une autre implémentation d’OpenPGP |
| Format de signature | SSHSIG avec l’espace de noms git, en armure ASCII BEGIN SSH SIGNATURE | Paquet de signature OpenPGP, en armure ASCII BEGIN PGP SIGNATURE |
| Taille dans l’objet commit (Ed25519, mesurée) | 306 octets | 279 octets |
| À qui l’on fait confiance | Clés listées dans gpg.ssh.allowedSignersFile | Clés du trousseau dotées d’un niveau de confiance (owner trust) suffisant |
| Expiration et rotation | valid-after et valid-before par clé dans le fichier allowed signers (OpenSSH 8.8+) | Date d’expiration inscrite dans la clé, prolongeable ; sous-clés |
| Révocation | gpg.ssh.revocationFile (liste de clés ou KRL) | Certificat de révocation publié avec la clé |
| Clés matérielles | Clés FIDO2 (ed25519-sk, ecdsa-sk), agents adossés à des enclaves sécurisées | Cartes à puce OpenPGP et clés de sécurité dotées d’une applet OpenPGP |
| Autorités de certification | Certificats SSH via des lignes cert-authority | Aucune ; identités certifiées par d’autres clés |
| Badge « Verified » de GitHub | Depuis le 23 août 2022 | Depuis avril 2016 |
| Badge « Verified » de GitLab | Depuis la 15.7 (décembre 2022), disponibilité générale avec la 15.8 | Oui |
Signer et vérifier des deux façons
Le script ci-dessous crée une clé SSH et une clé OpenPGP pour la même identité dans un répertoire temporaire, signe un commit avec chacune et vérifie les deux (Git 2.54, OpenSSH 10.3, GnuPG 2.5.21). La configuration Git globale est désactivée : rien ne change sur votre machine.
#!/bin/sh
base=$(pwd)
dir=$(mktemp -d "$base/commitdemo.XXXXXX")
cd "$dir" || exit 1
GNUPGHOME=$(mktemp -d /tmp/gpg.XXXXXX) # short path: gpg-agent sockets need one
export GNUPGHOME GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1
export GIT_AUTHOR_NAME=Alice GIT_AUTHOR_EMAIL=alice@example.org
export GIT_COMMITTER_NAME=Alice GIT_COMMITTER_EMAIL=alice@example.org
# One SSH key with an allowed_signers entry, one OpenPGP key
ssh-keygen -q -t ed25519 -N '' -C alice@example.org -f alice
echo "alice@example.org namespaces=\"git\" $(cat alice.pub)" > allowed_signers
gpg --batch --quiet --passphrase '' --quick-gen-key "Alice <alice@example.org>" ed25519 sign 1y
fpr=$(gpg --list-keys --with-colons alice@example.org 2>/dev/null | awk -F: '/^fpr/ { print $10; exit }')
# Two commits: the first signed with SSH, the second with OpenPGP
git init -q repo && cd repo || exit 1
git config gpg.ssh.allowedSignersFile ../allowed_signers
echo one > file && git add file
git -c gpg.format=ssh -c user.signingkey=../alice.pub commit -q -S -m "signed with SSH"
echo two >> file
git commit -q -a -S"$fpr" -m "signed with OpenPGP" 2>/dev/null
for c in HEAD~1 HEAD; do
echo "== $(git log -1 --format=%s "$c")"
git verify-commit "$c" 2>&1 | grep -E "Good|using"
git cat-file commit "$c" | awk '/^gpgsig/,/END/' > sig.txt
echo "$(head -1 sig.txt | cut -c8-) ($(wc -c < sig.txt | tr -d ' ') bytes in the commit object)"
done
gpgconf --kill gpg-agent
cd "$base" && rm -rf "$dir" "$GNUPGHOME"
== signed with SSH
Good "git" signature for alice@example.org with ED25519 key SHA256:7z1vKkx5UJmp2Qrc5ucSDqImz8+r8pfG21roc32f/2A
-----BEGIN SSH SIGNATURE----- (306 bytes in the commit object)
== signed with OpenPGP
gpg: using EDDSA key 6A4E1CC8308072568C9E240CDDBB1B4BE59BFC00
gpg: Good signature from "Alice <alice@example.org>" [ultimate]
-----BEGIN PGP SIGNATURE----- (279 bytes in the commit object)
La vérification SSH indique le principal tiré de allowed_signers et l’empreinte de la clé ; la vérification OpenPGP indique l’ID utilisateur et le niveau de confiance issu du trousseau. Les tailles sont proches, car les deux transportent une seule signature Ed25519 ; SSHSIG intègre en plus la clé publique complète, OpenPGP seulement son empreinte. Le vérificateur de signatures SSH et l’inspecteur OpenPGP décodent l’un ou l’autre bloc extrait par git cat-file commit.
Décider quelles signatures font foi
Une signature valide n’a de valeur que si le vérificateur sait quelles clés appartiennent à qui. Avec SSH, cette correspondance est le fichier allowed_signers : une ligne par principal et par clé, éventuellement restreinte à l’espace de noms git et à une fenêtre de validité. Git compare valid-after et valid-before à l’heure à laquelle la signature a été faite : une clé retirée peut donc rester dans le fichier avec une date de fin, et les anciens commits restent vérifiables. Une ligne cert-authority fait confiance à toute clé certifiée par l’autorité de certification de certificats SSH d’une organisation, ce qui convient aux entreprises qui délivrent déjà des certificats SSH de courte durée. Le fichier peut résider dans le dépôt : ses modifications sont alors elles-mêmes relues et signées.
Avec OpenPGP, la correspondance réside dans le trousseau et la base de confiance de chaque vérificateur, c’est pourquoi les systèmes de CI et les forges importent les clés explicitement. La toile de confiance peut relier des inconnus, mais elle est rarement utilisée en dehors de communautés établies de longue date. Les clés portent leurs propres dates d’expiration et certificats de révocation, et les sous-clés permettent à un développeur de garder la clé principale hors ligne et de renouveler les sous-clés de signature sans changer d’identité.
Les forges ajoutent leur propre couche : GitHub et GitLab affichent « Verified » lorsque la clé de signature est enregistrée sur le compte associé à l’adresse e-mail vérifiée du committer. Ce badge dépend des données de la forge ; la vérification persistante de GitHub, en préversion depuis novembre 2024, enregistre le résultat au moment du push, si bien qu’une suppression ultérieure de la clé ne le modifie pas.
Quand choisir l’un ou l’autre
- Développeurs individuels sur GitHub ou GitLab : SSH, idéalement avec une clé
ed25519-sksur une clé de sécurité, pour que chaque signature exige de toucher la clé. - Équipes et entreprises : SSH avec un fichier
allowed_signersdans le dépôt, ou avec des certificats SSH délivrés par votre AC existante. - Projets qui vérifient les tags amont avec OpenPGP (noyau Linux, nombreuses distributions, responsables de versions dont les clés sont publiées) : OpenPGP.
- Commits créés en CI ou par des bots : aucune des deux clés de longue durée ; utilisez la signature sans clé avec des certificats de courte durée (par exemple gitsign de Sigstore, voir Sigstore vs signature GPG) ou les signatures propres aux bots de la forge.
- Environnements réglementés avec cartes à puce X.509 :
gpg.format=x509avec un outil de signature S/MIME, pris en charge depuis Git 2.19.
Notes de migration
- Configurez la signature SSH :
git config --global gpg.format ssh,user.signingkeypointant vers le fichier de votre clé publique (oukey::suivi de la clé), ainsi quecommit.gpgsign trueettag.gpgsign true. - Enregistrez la clé comme clé de signature sur votre forge ; GitHub et GitLab acceptent la même clé pour l’authentification et la signature, mais une clé de signature distincte est plus facile à renouveler.
- Publiez la liste des signataires autorisés dans le dépôt (par exemple
.gitsigners), faites pointergpg.ssh.allowedSignersFilevers elle en CI et exécutezgit verify-commitsur les merges ; ajoutezvalid-afterlorsque vous ajoutez une clé etvalid-beforelorsque vous en retirez une. - Gardez les anciennes clés publiques OpenPGP à la disposition des vérificateurs et sur les comptes de la forge, afin que les commits signés avant le changement restent vérifiables.
- Imposez les commits signés sur les branches protégées (ensembles de règles GitHub, règles de push GitLab) une fois que tous les committers ont migré.
Références
- Documentation Git : git-config gpg.format, gpg.ssh.allowedSignersFile, gpg.ssh.revocationFile
- Notes de version de Git 2.34
- Notes de version d’OpenSSH 8.1 et manuel de ssh-keygen, ALLOWED SIGNERS
- OpenSSH PROTOCOL.sshsig
- RFC 9580, OpenPGP
- Journal des modifications de GitHub : vérification des commits signés avec SSH
- GitLab : signer les commits et les tags avec des clés SSH