Signing commits with GPG

Mon 20 Sep 2021

I've recently started signing my commits. After being through this process I think it is important that other people do also. Why? Simply because it makes it easier and verifiable who did what. You might think that git already does that for you, and you would be correct. However, you can easily set up your local environment to mimic another account. Yes. You read that right. You can set up your local git to impersonate someone. The git repo won't know. That's where GPG comes in.

GPG is a separate piece of software that uses cryptography to generate your digital identity. This identity is unforgeable, proving that when you sign a document it originates from you. That is what we aim to do with commits.

Basic Configuration

When setting up git locally for the first time on any machine you probably run something along the lines of these commands.

rob@Rathalos ~ $ git config user.name "Joe Smoke"
rob@Rathalos ~ $ git config user.email "joe@fakesmokeybbq.com"

You will still need to do this bit. Git works with these identities to associate an account with the commits. The problem here is that you can fill in the blanks with any value. Impersonating your friendly colleagues for example. This is where signing your commits come in. This makes an unforgeable signature on the commits that lead back to your GPG identity. A web of trust strengthens trust to that signature.

Let's talk GPG identities

I've already written [an article]() on how to get started with GPG. This will get you up and running with a single identity. It is a common practice to create purpose-built keys. One key to sign git commits, another to sign emails, another for something else. You can achieve these by creating subkeys under the key you've already generated with gpg2 --full-gen-key by running:

rob@Rathalos ~ $ gpg2 --edit-key 3127C2HJ
# Shows you key info...

# Run addkey to add a subkey
gpg> addkey
# Run adduid to add a uid
gpg> adduid

Additionally to adding keys you can also add uid's to support multiple identities to these keys. This is useful (or not) when you want to add your work's email for example.

Follow the wizard that comes out of this to generate a subkey. You can delete these afterward as long as you didn't push it to a public key server. Creating these purpose-built keys will structure and declutter signatures found around the web that correlate back to your digital identity. It will also allow you, yourself, to verify more easily if something is wrong.

It is considered good practice to set yourself up with at least one to sign your git commits with and then continue configuring git to use that key/identity to sign commits with.

Configuring Git to sign

Configuring git only calls for the next three commands.

# Point git to the right key
rob@Rathalos ~ $ git config --global user.signingkey 3127C2HJ

# Enable automatic signing of commits and tags
rob@Rathalos ~ $ git config --global commit.gpgSign true
rob@Rathalos ~ $ git config --global tag.gpgSign true

# Optionally: Make sure that the identity in git matches to one of the uid's
rob@Rathalos ~ $ git config --global user.email your@email.com

# Export the key for Github/Gitlab
rob@Rathalos ~ $ gpg --armor --export 3127C2HJ

Your public GPG key begins with -----BEGIN PGP PUBLIC KEY BLOCK----- and ends with -----END PGP PUBLIC KEY BLOCK-----.

Add the exported key to your profile on the repository hosting. This allows the repo to verify the signature when the commits are pushed. I was surprised that Bitbucket does not support this and does not have plans to resolve this. Making this premium hosting a less attractive choice against Gitlab or Github.

Using Git with GPG

Now you've got automatic signing on. Each commit will prompt a for the password to the key to sign the work off. There are a few commands that you should also be aware of.

You can use --verify-signatures on a merge to check if all commits have been signed for instance. In addition, you can also sign the merge commit itself by adding the -S just like you would with a single commit (when not set up automatically). Currently, git does not support config that allows you to set up merge.gpgSign. This needs to be done manually.

# Signing a git commit
rob@Rathalos ~ $ git commit -S -m 'Changing a typo in README'

# Checking git log for signature
rob@Rathalos ~ $ git log --show-signature -1
commit 85e35333cc318b41fb3df3ca26db762dcff96ab1 (HEAD -> master)
gpg: Signature made Mon Sep 20 11:32:21 2021 UTC
gpg:                using RSA key 3127C2HJ
gpg: Good signature from "Joe Smoke <joe@fakesmokeybbq.com>" [ultimate]
Author: Joe Smoke <joe@fakesmokeybbq.com>
Date:   Mon Sep 20 11:32:21 2021 +0000

    Changing a typo in README

# Verify signatures when merging a branch without signed commits
rob@Rathalos ~ $ git merge --verify-signatures branch-with-normal-commits
fatal: Commit b014823 does not have a GPG signature.

# Verify signatures when merging a branch with signed commits
rob@Rathalos ~ $ git merge --verify-signatures -S branch-with-signed-commits
Commit ff96ab1 has a good GPG signature by Joe Smoke (Git signing key) <joe@fakesmokeybbq.com>

You need a passphrase to unlock the secret key for
user: "Joe Smoke (Git signing key) <joe@fakesmokeybbq.com>"
2048-bit RSA key, ID 3127C2HJ, created 2021-09-10

Merge made by the 'recursive' strategy.
 README | 2 ++
 1 file changed, 2 insertions(+)

Web interface "Verified"

When pushing these commits they will get the verified badge on the repo. When you hover over you can see the key that is associated with that commit that also links to the account that is verified by the git hosting. This always allows you to see who pushed the changes to the repo.

Let me stress that this still is no waterproof system. However, it will make you more aware and gives you the power to verify at least. It's a layer of protection against supply chain attacks.

Hardware keys like Yubikey

Hardware keys will make this a smoother experience. Personally I think it is well worth the money. It will assist you in your daily work. I've got the Yubikey 5 NFC and I've been loving it. They are robust, secure and save time.

I'll leave you with that. I think more people should be signing. Especially in larger organizations, where there is a multitude of attack vectors. You should consider even if you are just contributing to open-source software or working on your own projects.