Signing git commits with SSH key

GitHub started supporting SSH commit verification on August 2022.

GitHub now supports SSH commit verification, so you can sign commits and tags locally using a self-generated SSH public key, which will give others confidence about the origin of a change you have made. If a commit or tag has an SSH signature that is cryptographically verifiable, GitHub makes the commit or tag "Verified" or "Partially Verified."

Let's have a look, how this works in practice.

Note: This article will build on top of my earlier article Just enough git and GitHub to be productive, and I will naturally still use macOS as my operating system. Just as before, familiarize yourself with the SSH and git setup on your OS of choice to follow along.

Before continuing, check the SSH and git configuration we went through last time. The GitHub part of this whole process is actually trivially simple but in order to get a signed commit to GitHub, we will need to figure out, how we can use an SSH key to sign commits locally. It is important to use the same SSH key for signing, which we already used to connect to GitHub.

Git configuration changes

As a first step, copy the public key to clipboard:

pbcopy < ~/.ssh/id_ed25519_github.pub

In order to sign commits locally, we need to add a couple of new things to the global git config:

# Configure git to use SSH to sign commits and tags
git config --global gpg.format ssh
# Set the SSH signing key to your public key
# Remember the single quotes!
git config --global user.signingkey '[paste public key here]'

# If you want to sign commits by default:
git config --global commit.gpgsign true

# We can check the current config with
git config -l --global

Note: You can alternatively make the changes to the project specific git config, if you so choose.

SSH config changes

Unlike PGP/GPG, SSH does not provide a trust framework, which would allow us to specify which keys we choose to trust, or even allow other keys to be verified.

Instead, SSH - or more specifically ssh-keygen - uses a simple file to list the identities and keys to determine whether a signature comes from an authorized source. This file does not exist by default, so we need to create and populate it.

The content of the allowed_signers is your SSH public key contents, but we need to modify the order of elements. Copy your public to a text editor. It will look something like this:

ssh-ed25519 AAAAC3Nza...rEUvJl7W/J your.email@address.com

allowed_signers requires the identities to be listed first, so edit the string to be as follows:

your.email@address.com ssh-ed25519 AAAAC3Nza...rEUvJl7W/J

Then:

# Create the file to your .ssh directory
touch ~/.ssh/allowed_signers
# Populate the content with the edited string
echo "your.email@address.com ssh-ed25519 AAAAC3Nza...rEUvJl7W/J" >>~/.ssh/allowed_signers

# Tell git to use this file by adding a new config value
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers

Everything should now be ok locally, let's move to configure GitHub.

GitHub config

This is the trivially easy part. We just need to add our SSH public key to our GitHub settings.

Open GitHub on your browser, and navigate to https://github.com/settings/keys, and add a New SSH key. Give the key a name you will recognize later, choose Signing Key as key type, and paste your SSH public key to the key field. After this, you will have the same public key twice in your config: once for authentication, and once for signing.

Configuration is now ready to be tested.

Create a new signed commit

In order to test the signing, let's make a small change to the project we were working on my previous article:

# Switch to project directory
cd ~/projects/the_project
# Change existing file
echo "testing commit signing" >>foo.txt
# Stage the change
git add foo.txt
# Commit the change with signing (-S)
git commit -S -m "New signed commit"

# (Optionally) Verify the signature
git show --show-signature

# Push the change to GitHub
git push

If all went well, GitHub will now show the commit as verified: Signed commit on GitHub screenshot

A troubleshooting tip: I first encountered an error while trying to create a signed commit. The error message said error: Load key "/var/folders/.../T//.git_signing_key_tmpZC": invalid format?. After some googling and trying to figure out what was going on, I (re)added the SSH key to ssh-agent with ssh-add --apple-use-keychain ~/.ssh/id_ed25519_github. This fixed the issue, and the commit signing worked.

Summary

So, in summary: Since GitHub has made commit and tag verification with SSH key possible (and trivially easy on their part), we can easily add a new layer of security to our development process without the pain of PGP/GPG. Yes, I kind of hate to say it out loud, but PGP/GPG is horrible thing to setup and use on practical level.

Further reading