Yubikeys for Signed Git Commits

Apr 30, 2019| Daniel Jones

By signing our Git commits, we can allow folks to verify that they were really written by the author tagged on the commit. If you’ve got a Yubikey set up as per our other blog posts, it’s a doddle to configure.

Ensure Public Key is on Keychain

Your public key needs to be on your GPG installation’s keychain.

First, see if it already on your chain (using your own address!):

$ gpg --list-secret daniel.jones@engineerbetter.com

If you see something like this, then you already have your public key available and can proceed to Share With GitHub:

sec>  rsa2048/ADD0D0CAFEDECADE 2017-11-22 [SC] [expires: 2021-04-29]
      FEEDBEEFC0C0A7D867D34ADEADD0D0CAFEDECADE
      Card serial no. = 0006 06917459
uid                 [ultimate] Daniel Jones <daniel.jones@engineerbetter.com>
ssb>  rsa2048/AF5A4B5AA8A8C5BF 2017-11-22 [A] [expires: 2021-04-29]
ssb>  rsa2048/BA53B2D6734C8A8E 2017-11-22 [E] [expires: 2021-04-29]

If you don’t see the above, we’ll need to get hold of it.

Recent versions of the prior blog post suggested uploading your public key to a keyserver. You can find out if your key is on a given server with:

$ gpg --keyserver keys.gnupg.net --search daniel.jones@engineerbetter.com

If you experience the following…

$ gpg --keyserver keys.gnupg.net --search daniel.jones@engineerbetter.com
$ gpg: error searching keyserver: Server indicated a failure
$ gpg: keyserver search failed: Server indicated a failure

Try adding the hkp protocol along with a port override:

$ gpg --keyserver hkp://keys.gnupg.net:80 --search daniel.jones@engineerbetter.com

Results (if any) are numbered, and simply selecting the right number from the list will import your key.

If you didn’t upload your public key to any keyservers but still have access to the machine upon which you generated the key (or any other where it is in the keychain) then you can export it, ready for import:

$ gpg --armor --export daniel.jones@engineerbetter.com > public.asc

Copy the file to the other machine, and then import it:

$ gpg --import /path/to/public.asc

Obviously this is a fragile solution, so uploading it to a keyserver once you’re done is a good idea.

Share With GitHub

You need to tell GitHub about your public key. The argument here is the long ID from above (gpg --list-secret <email-address>):

$ gpg --armor --export FEEDBEEFC0C0A7D867D34ADEADD0D0CAFEDECADE
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBFoVTx8BCAD29H458Y3YwqGoG1HDEDiiAGaZoMONCh0Ql27CI7eSxhB08lI2
[...SNIP!]
DVeNShSNf4K9uOS62gEQROZQClA/
=xOmv
-----END PGP PUBLIC KEY BLOCK-----

Copy the above public key, including the begin and end blocks, and then add it as a new key on GitHub.

We then need to tell Git to use GPG to sign commits, and specifically this key. Use the short ID from the output of the --list-secret command we ran earlier. In my example, it follows after rsa2048:

If the short ID is not present in the output, try running the command with --keyid-format LONG.

git config --global commit.gpgsign true
git config --global user.signingkey ADD0D0CAFEDECADE

Nearly there! Let’s now restart the GPG agent:

gpg-connect-agent reloadagent /bye

Testing

Make a commit in any repository, and hopefully you shouldn’t see an error message.

Run git log --show-signature to check that the commit was signed:

$ git log --show-signature
commit d1972b6a7a3534413aec91f06d7bd0fdf9bcdc0e (HEAD -> master)
gpg: Signature made Tue 30 Apr 11:50:07 2019 BST
gpg:                using RSA key FEEDBEEFC0C0A7D867D34ADEADD0D0CAFEDECADE
gpg: Good signature from "Daniel Jones <daniel.jones@engineerbetter.com>" [ultimate]
Author: Daniel Jones <daniel.jones@engineerbetter.com>
Date:   Tue Apr 30 11:50:07 2019 +0100

    informative message

Errors?

If when you made the commit you were greeted with the error git error: gpg failed to sign the data, there could be a number of causes:

Push

Assuming that everything has worked thus far, you can now git push and bask in the resplendent glory of a lovely “Verified” badge on GitHub:

Why Bother?

You might ask what the benefit of all this is. After all, you’re already authing to GitHub with your SSH key, right?

Your SSH key proves that you can talk to GitHub, and that you’re allowed access to the repository in question. It doesn’t prove that the commits you are pushing were really written by the flagged authors though.

It’s trivial to make a commit with a false identity:

git commit -m "implement sensible error handling" --author="Rob Pike <rob@google.com>"

You can then push this, authenticating with your SSH key (or HTTP basic credentials), which is of course totally valid.

You’ve then managed to masquerade as a colleague, presumably pushing awesome code to help them get a raise. Or, perhaps, you’ve done something nefarious. But you’d never do a thing like that, would you?

Get in touch

See how much we can help you.
Call +44 (0) 20 7846 0140 or

Contact us