Signing GitHub commits with SSH keys

05Sep22

TL;DR

Using SSH keys is already a big part of the git/GitHub experience, and now they can be used for signing commits, which saves having to deal with GPG keys.

Background

For a while I’ve been signing my git commits with a GPG key (at least on my primary desktop), and GitHub has some nice UI candy to add a Verified badge for anybody looking there to see.

When I recently created the Atsign guide to GitHub there’s even a section recommending signed commits.

Git 2.35 introduced the ability to sign commits with SSH keys, which people are far more likely to have than GPG keys, and recently GitHub (finally) got functionality in place for people to register SSH keys as signing keys, and show those Verified badges.

First you need a newer git client

I mostly use Ubuntu 20.04 LTS for things, and that comes with git version 2.25, which is nowhere near new enough. Thankfully it’s pretty easy to add the the git-core package archive and grab the latest stable git from that:

sudo add-apt-repository ppa:git-core/ppa
sudo apt update
sudo apt install git

That just worked for me, but if you run into trouble, take a look at this StackOverflow guide for some tips.

Now set up git to use an SSH key for signing

I found a few guides for this, but the one I shared with colleagues is Caleb Hearth’s ‘Signing Git Commits with Your SSH Key

The main point is to enable signing, and tell git to use SSH:

git config --global commit.gpgsign true
git config --global gpg.format ssh

Initially I did this without the –global flag to experiment on a single repo.

Git also needs to be told about your public key:

git config --global user.signingkey "ssh-ed25519 <your key id>"

All of the examples I’ve seen use shiny new (and short) ed25519 keys, but good old rsa keys can also be used.

What about my private key?

The line above uses a public key, and you also upload a public key to GitHub so it can display that Verified badge, but git needs your private key to do the signing, so there’s a little bit of key management magic happening behind the scenes.

Peeling back the magic, there’s an assumption that you’re running ssh-agent, which might be a fair assumption for folk who get deeply into doing stuff with SSH keys, but breaks when encountering a lot a default setups. My WSL2 install of Ubuntu doesn’t have ssh-agent there by default, so I needed to run:

eval $(ssh-agent -s)
ssh-add

But that’s only a temporary fix for the life of that shell session. I’ve added the following to my .bashrc:

{ eval $(ssh-agent -s); ssh-add -q; } &>/dev/null

I’ve seen a suggestion that ‘Using SSH-Agent the right way in Windows 10/11 WSL2‘ should be done with the keychain tool, but my fairly simple setup is just fine without it.

The GitHub bit

GitHub just needs the SSH public key (just like when setting up SSH keys for authentication), except the key is added as a signing key:

But wait, there’s more…

I’m pretty sick of seeing messages like this:

$ git push
fatal: The current branch cpswan-anotherbranch has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin cpswan-anotherbranch

and because I always just copy/paste the correct line from those error messages, I’ve never learned the actual incantation to get it right first time. I extra hate it when software knows exactly what I’m trying to do, refuses to do it, scolds me and tells me what I should be typing.

Thankfully recent git can now be configured to just get on with it:

git config --global --add --bool push.autoSetupRemote true

Conclusion

Setting up GPG was enough of a hassle that I’d only done it on my desktop, but setting up SSH signing is easy enough that I’ll be happy to do it everywhere that I use git. There are a few extra hoops to jump through to make everything seamless, but they’ll get smoothed out over time.



No Responses Yet to “Signing GitHub commits with SSH keys”

  1. Leave a Comment

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.