Configure GitHub Activity Signing with Windows Subsystem for Linux (WSL)

on under articles
8 minute read

Now that I’m in a role where my job entails writing code for Microsoft products in the open on GitHub, I thought that it may be a good idea to make sure that my commits and related activities on GitHub were signed and could be verified as my contributions. That isn’t meant to imply that I have major concerns about spoofing, but I remembered that it happened to Scott Hanselman last year and that he set up signing in response to it.

Scott ended up configuring GPG signing with a YubiKey, which looked like an intimidating process. I wanted to do something more basic and see if using the stock on-box storage was as straightforward as configuring SSH authentication for GitHub.

Setting the Stage

In my normal development flow, I use the git command line, either under WSL on Windows or natively on Linux. While I may use a GUI tool occasionally to help visualize the commit graph for a repository, I tend to do all of the activities that I’m interested in signing outside of them. I prefer a dedicated stand-alone command line window to embedded instances, such as the terminal in Visual Studio Code.

As a result, the process that I’m describing here is focused on integrating GPG signing into a git workflow from a stand-alone terminal window. Some things may or may not work elsewhere but, I’ve honestly not spent any time exploring or verifying other tools. The other goal that I had was to try and minimize the number of times in a day that I’d have to unlock my GPG key with a password.

GitHub has some great documentation on the process, walking through the steps needed locally as well as within the GitHub site in order to enable signing. For the most part, I’ll be referring back to them where possible, up through configuring the basic signing mechanism. There are a few things needed to enable local caching of your GPG credentials to avoid a password prompt for each commit that those guides didn’t cover.

Prerequisites

Before starting, I find it helpful to have the necessary packages installed and ready to go, rather than pulling them down as needed. To that end, I’d recommend installing the following on a Debian-based distribution, such as Ubuntu:

  • build-essential
  • apt-transport-https
  • software-properties-common
  • ca-certificates
  • curl
  • git
  • gpg
  • gnupg
  • gpg-agent
  • pinentry-curses

Generating the Key

I’d recommend following the GitHub Help guide - Generating a new GPG key. It has a nice step-by-step flow for each operating system. In my case, the Linux steps went smoothly and I’d echo the GitHub advice of using a 4096 bit key. As the guide mentions, you can verify the key that you created using:
gpg --list-secret-keys --keyid-format LONG

Configuring GitHub

Here, again, GitHub Help provides an excellent guide - Adding a new GPG key to your GitHub account, which builds upon the previous guide for key generation. Before starting the configuration guide, you’ll want to make sure that you have your key available.

To do so, start by listing your available GPG keys, using:
gpg --list-secret-keys --keyid-format LONG

From the list, copy the id of the key that you’ll be using to sign, which will be in a line that looks like:
sec [Key Length]/[Key ID] [Date Created and Expiry Date]

If the sec line of your output is the following, then your key Id is 3AA5C34371567BD2.
sec 4096R/3AA5C34371567BD2 2016-03-10 [expires: 2017-03-10]

Once you have the key, you’ll need to export the full key in armor format. You can do so using:
gpg --armor --export << YOUR KEY ID >>

GitHub will expect the public portion of your key, starting with -----BEGIN PGP PUBLIC KEY BLOCK----- up through -----END PGP PUBLIC KEY BLOCK-----, including those markers copied as part of your key.

Once you follow the steps in the guide, GitHub will have your key registered and is ready to verify your signed activities.

Register Your Key with Git

The most important step in configuring the terminal is to tell git to make use of your key. Again, GitHub Help has a useful guide - Telling Git about your signing key, from which the steps that we’re interested in fall under the Telling Git about your GPG key title. In a nutshell, the steps are:

  1. List your available GPG keys and copy the Id of the key that you’ll be using to sign, the same way that you had done when configuring GitHub.
  2. Configure your .gitconfig to associate the key by using the command:
    git config --global user.signingkey << YOUR KEY ID >>

Optionally, if you’d like to instruct git to always sign commits and tags, you can run the following to update your git configuration:

  • git config --global commit.gpgsign true
  • git config --global tag.gpgsign true

Configuring Entry and Caching for your GPG Credentials

At this point, you’re able to perform end-to-end signing for commits, tags, and related GitHub activities. The unfortunate part is that your git client will prompt for a password before each of those operations, which tends to have a negative impact on productivity. To get around this, it is possible to cache your GPG key password, allowing you to use the git client normally, without additional entry, but producing signed commits.

Unfortunately, this is an area where there wasn’t a helpful GitHub guide and most of the resources that I found were focused on macOS and/or out of date. The basic gist of what we’d like to do is use the gpg-agent as a cache for the credentials and integrate that with the WSL terminal, having the curses user experience prompt for entry of the GPG password, so that it’s very clear when it’s needed.

To start, we’ll need to configure GPG to make use of the agent for caching and set the key used by default. In ~/.gnupg/gpg.conf, add or update the following:

# Uncomment within config (or add this line)
# This tells gpg to use the gpg-agent
use-agent

# Set the default key
default-key << YOUR KEY ID >>

The next step is to configure the GPG Agent to cache your password and instruct it how we would like to be prompted for password entry. The GPG Agent allows for the time of the cache to be specified, so that you’re able to make the choice that is right for you. In the example, caching is set to 400 days (34560000 seconds) so that it can be entered once and then is not needed again until the computer or WSL session are restarted. In ~/.gnupg/gpg-agent.conf, the cache times and an executable for password prompting are registered. The GPU configuration should contain the following, though you may need to change the location of your pin entry program to the output of the command which pinentry-curses, depending on your operating system:

default-cache-ttl 34560000
max-cache-ttl 34560000
pinentry-program /usr/bin/pinentry-curses

The final step is to ensure that the GPG agent launches when your WSL session starts and that the environment is prepared. Note that this is an area where things have changed fairly recently, and most of the resources that I found on the web were outdated. The approach that I’m using here was tested with GPG v2.2.4 and GPG Agent v2.2.4. In either ~/.profile or ~/.bashrc, add the following:

# enable GPG signing
export GPG_TTY=$(tty)

if [ ! -f ~/.gnupg/S.gpg-agent ]; then
    eval $( gpg-agent --daemon --options ~/.gnupg/gpg-agent.conf )
fi

export GPG_AGENT_INFO=${HOME}/.gnupg/S.gpg-agent:0:1

That’s All, Folks

If you’ve gotten this far, then git in your Windows Subsystem for Linux terminal should be all set to sign commits. While there may be a few steps involved, they felt reasonably straightforward to me, once I had figured out the environment configuration. Hopefully, this guide helped to lay out the end-to-end steps and will save others from having to piece them together from multiple resources.

Helpful Resources

git, github, wsl, configuration
comments powered by Disqus