Signing Git Commits
Signing your commits on git with PGP.
Signing your git commits gives everyone the added trust that the work you commit, is truly by you and not a malicious actor pretending to be you or that it hasn’t been modified in transport. For a look at how serious the implications are read the Spoof a commit on Github article and try spoof a git commit yourself!
Setting up signing your commits into git isn’t all that difficult either. This guide takes you through the process and has some bonus tips down below!
Install the toolchain - GPG
First we need to setup the GnuPG Toolkit on your machine.
Most Linux installations ship with gpupg tools, gnupg2 is better. It's also best to set it as the app to use:
sudo apt-get install gnupg2
git config --global gpg.program gpg2
brew install gpg
choco install gnupg
Generate or Import a Key
Once the toolkit is installed, we can opt to generate and create a new GPG Key, or import one - especially if you’re on Keybase.
Generate a new key
Once installed, we need to generate an initial GPG Key.
$ gpg --full-generate-key gpg (GnuPG) 2.2.19; Copyright (C) 2019 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. gpg: directory '/home/thushan/.gnupg' created gpg: keybox '/home/thushan/.gnupg/pubring.kbx' created Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) (14) Existing key from card
Make sure you select option
(1) RSA & RSA (default) and opt for a 4096 bit key.
Your selection? 1 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (3072) 4096 Requested keysize is 4096 bits Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) 6m
After which you’ll be asked to select a timeframe, we either rotate keys every 6 months or every 1 year. Then enter your identifiable information and ensure the email address you enter matches that of your Github account.
NOTE: If you get an error about the gpg agent not running like below:
gpg: can't connect to the agent: IPC connect call failed gpg: agent_genkey failed: No agent running Key generation failed: No agent running
You can run the agent with:
$ gpg-agent --daemon
And try again.
Once generation has completed, you’ll find your newly minted key in the
.gnupg folder in your home directory.
You can list the key with these two commands:
$ gpg --list-secret-keys /home/thushan/.gnupg/pubring.kbx -------------------------------- sec rsa4096 2020-06-02 [SC] [expires: 2020-11-29] AA8912187EE6AB9EBB49B109E27FF31D0EB10C13 uid [ultimate] Thushan Fernando (Blog example update #22) <firstname.lastname@example.org> ssb rsa4096 2020-06-02 [E] [expires: 2020-11-29] $ gpg --list-secret-keys --keyid-format LONG /home/thushan/.gnupg/pubring.kbx -------------------------------- sec rsa4096/E27FF31D0EB10C13 2020-06-02 [SC] [expires: 2020-11-29] AA8912187EE6AB9EBB49B109E27FF31D0EB10C13 uid [ultimate] Thushan Fernando (Blog example update #22) <email@example.com> ssb rsa4096/76A398C8592EE9B8 2020-06-02 [E] [expires: 2020-11-29]
The latter command gives you the [KEYID] too - which in this example is
Import GPG Key from Keybase
Importing an existing GPG Key from your Keybase is easy as pie! Make sure Keybase is properly installed on your system (you need the CLI tools which are installed with the keybase App) and follow along:
Export the public key from Keybase and import it to your local GPG:
$ keybase pgp export | gpg --import
The output from the command will give you the key you’re importing (the KEYID in the preceding examples).
If you have multiple keys (check with
keybase pgp list), you can export individual keys with:
$ keybase pgp export -q [KEYID]
Subsequently, export the secret key from Keybase and import it into GPG - and you’ll be prompted to enter your passphrase.
$ keybase pgp export --secret | gpg --import --allow-secret-key-import
For multiple keys, you’ll have to use the
-q [KEYID] switch as earlier.
$ keybase pgp export -q [KEYID] --secret | gpg --import --allow-secret-key-import
Get your public key block
Once your key has been created or imported, we need to pull out the public key with the GPG [KEYID], save it to a file so you can copy it easily.
gpg --armor --export [KEYID] > gpg-key.txt
This public key you can socialise with the Github Account. Unfortunately it’s not available in BitBucket yet, but see if they eventually will with Feature Request BCLOUD-3166.
Now you can use your key within git by associating it with the
user.signingkey setting and tell it to auto sign your future commits too:
$ git config --global user.signingkey [KEYID] $ git config --global commit.gpgsign true
Now each time you create a commit, you’ll be prompted to enter your passphrase. If you selected not to run the last command and autosign each commit, you can manually sign your commits by appending the
-S switch in your commit.
$ git commit -s -m "This is the only thing I commit to."
And if you want to sign all your previous commits now that your keys are setup, see Signing Previous Git Commits guidance.
Get gpg to save your passphrase
You can use the
gpg-agent remember your passphrase to make it easy whilst you’re at work.
~/.gnupg/gpg-agent.conf by adding the following two lines which asks the agent to save the passphrase for a timeframe.
*-ttl is in seconds, so for the example below, it’s 9hrs (
60 * 60 * 9 = 32400).
default-cache-ttl 32400 max-cache-ttl 32400
If you’re using Powershell, here’s a handy script that will create the config file (as it won’t exist in Windows) and set the cache automatically for you.
Set-Content -Path ~\.gnupg\gpg-agent.conf -Value "default-cache-ttl 32400$([System.Environment]::NewLine)max-cache-ttl 32400"
Once configured, you can restart the daemon and verify the values.
$ gpgconf --reload gpg-agent
And verify the settings are enabled:
gpgconf.exe --list-options gpg-agent
It should emit something along the lines of..
... default-cache-ttl:24:0:expire cached PINs after N seconds:3:3:N:600::32400 max-cache-ttl:24:2:set maximum PIN cache lifetime to N seconds:3:3:N:7200::32400 ...
You’re set to go sign commits!