Have you ever wondered why GitHub labels certain commits as [verified]? It's a security mechanism to certify that the author of the commit is the legit person associated with that GitHub account.

Wait, what? I know that your asking: "Is it possible to fake an identity with Git?". The answer is: yes.

With a simple command you can impersonate any other user over GitHub:

git commit -m "Initial commit" \
  --author="Linus Torvalds <torvalds@linux-foundation.org>"

And this is what GitHub shows:

Fake impersonated Git author over GitHub user interface

Of course Linus Torvalds didn't collaborate to my project. But this opaque identity handling may potentially be leveraged as a social engineering attack.

To solve this problem, Git added commit signoffs, which are visualized with the [verified] label by GitHub.

Regardless of the good reasons to sign my Git commits, it took a while before I started to do so. As big fan of the automation, here's the Bash script that I've used for a few months to automate the process.

The setup

Note: I use Mac OS X (with Homebrew) as my development operating system, so there may be some differences with Linux or other UNIX flavors.

First you need to install the basic packages:

brew install git gnupg gpg-agent

Now you can set up Git:

git config --global user.name 'Full Name'
git config --global user.email you@somedomain.com

Make sure to replace Full Name and you@somedomain.com with the name and email that you use for GitHub.

Then export the following environment variable into your .bashrc or .zshrc:

export GPG_TTY=$(tty)

The script

The script executes five steps:

1. Git setup

This step sets gpg (from Homebrew gnupg package) as the program to sign commits and tags, enabling signing features globally (for all your repositories).

git config --global gpg.program `which gpg`
git config --global commit.gpgsign true

2. Generate GPG key

This step generates a GPG key (RSA 2048) by using the Git full name and email that you set above. The key will expire in 30 days.

It's a good security measure to rotate often passwords and keys.

cat >.gpgconfig <<EOF
   %echo Generating a basic OpenPGP key
   Key-Type: 1
   Key-Length: 2048
   Subkey-Type: 1
   Subkey-Length: 2048
   Name-Real: `git config --get user.name`
   Name-Email: `git config --get user.email`
   Expire-Date: `date -v +30d "+%Y-%m-%d"`
   %commit
   %echo done
EOF

gpg --batch --gen-key .gpgconfig
rm .gpgconfig

3. Configure the key with Git

This step takes the last generated key and tells Git to use it for signing purposes:

signingkey=$(gpg --list-secret-keys ...)
git config --global user.signingkey $signingkey

4. Restart GPG agent

Next, this step shuts down the gpg-agent. The next time gpg is used, the agent will be automatically restarted. This will happen when you'll sign your next commit.

After the restart the agent will be able to read the last generated key.

gpgconf --kill gpg-agent

This is step is needed for convenience purposes. The first time the new key is used, you'll be prompted for the passphrase, and the agent will remember it.

5. Configure GitHub

Signing commits is only the first part of the security equation. You need to upload your public key on GitHub so their UI will show the Verified green label alongside with each signed commit.

gpg --armor --export `git config --get user.signingkey` | pbcopy
open https://github.com/settings/keys

The script will copy the public key in the operating system clipboard. As the last step, it will open a browser with a GitHub page where to paste the public key:

  1. Click on "New GPG key"
  2. Paste the clipboard contents
  3. Click on "Add GPG key"
  4. Type your password (if asked)

Conclusion

Automation is key to start with good habits. You have no excuse to not sign your Git commit anymore. You can check the source code 📝 of the script, and see it in action here:

See gpggit in action

UPDATE: Since I wrote this article, Homebrew's package gnupg changed the executable from gpg2 to gpg. I updated the snippets and the script accordingly. Thanks @alxgsv!

Good signing! 👋