5 minute read

Setting up gpg, git and 1password to have your git commits signed, whilestoring your GPG key passphrase into 1Password and unlocking it directly from your terminal.

Requirements and setup

This was done on WSL2.

❯ uname -a
Linux DESKTOP-AGPN69M 5.10.60.1-microsoft-standard-WSL2 #1 SMP Wed Aug 25 23:20:18 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
❯ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.3 LTS"

Make sure you have git and gpg installed, and an active 1Password account.

You’ll find written to use gpg2 when available on your system, but in my case both gpg and gpg2 were pointed to the same bin.

❯ ls -l "$(which gpg)"
.rwxr-xr-x 1.1M root  6 Jan  2021 /usr/bin/gpg
❯ ls -l "$(which gpg2)"
lrwxrwxrwx 3 root  6 Jan  2021 /usr/bin/gpg2 -> gpg
❯ gpg --version
gpg (GnuPG) 2.2.19

I will use jq but this is not essential.

❯ jq --version
jq-1.6

Creating a GPG key

This is a summary of GitHub - Generating a new GPG key, that I followed.

Run the following command and follow instructions.

❯ gpg --full-generate-key

Then list your fresh key.

❯ gpg --list-secret-keys --keyid-format=long
/home/baptiste/.gnupg/pubring.kbx
---------------------------------
sec   rsa4096/0052A8D354A5C655 2022-02-09 [SC]
      9BA03414AB56590B6DB5369F0052A8D354A5C655
uid                 [ultimate] Baptiste Maingret (Home Desktop-WSL2) <baptiste.maingret@gmail.com>
ssb   rsa4096/A5B8C64E8929B475 2022-02-09 [E]

Look at the sec line and note the GPG key ID: 0052A8D354A5C655.

Then we export the corresponding public key.

❯ gpg --armor --export 0052A8D354A5C655
-----BEGIN PGP PUBLIC KEY BLOCK-----
# your public key
-----END PGP PUBLIC KEY BLOCK-----

Copy everything including the starting and ending blocks.

Setting up git

First let’s tell git which key to use. Using your GPG key ID, run:

❯ git config --global user.signingkey 0052A8D354A5C655

N.B This will configure it globally, you may need to configure it per repository depending on your usage.

Then we will tell git to sign every commit of every repository.

❯ git config --global commit.gpgsign true

Setting up GitHub

Instructions may change. Check online documentation Adding a new GPG key to your GitHub account.

TL;DR. Settings > Access > New GPG key

Setting up 1Password CLI

Instructions may change. Check online documentation. 1Password CLI: Getting started

N.B. Version is hardcoded in URL, so make sure to check the official website to get latest URL.

❯ curl -S https://cache.agilebits.com/dist/1P/op/pkg/v1.12.4/op_linux_amd64_v1.12.4.zip > op.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 3810k  100 3810k    0     0  4897k      0 --:--:-- --:--:-- --:--:-- 4891k

❯ unzip op.zip -d op
Archive:  op.zip
 extracting: op/op.sig
  inflating: op/op

❯ gpg --keyserver hkps://keyserver.ubuntu.com --receive-keys 3FEF9748469ADBE15DA7CA80AC2D62742012EA22
gpg: key AC2D62742012EA22: public key "Code signing for 1Password <codesign@1password.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1  

❯ gpg --verify op/op.sig op/op
gpg: Signature made Fri Jan 14 22:38:08 2022 CET
gpg:                using RSA key 3FEF9748469ADBE15DA7CA80AC2D62742012EA22
gpg: Good signature from "Code signing for 1Password <codesign@1password.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 3FEF 9748 469A DBE1 5DA7  CA80 AC2D 6274 2012 EA22

❯ sudo mv op /usr/bin

❯ op --version
1.12.4

Try to sign in.

op signin my.1password.com your.email@example.com

Configuring gpg-agent

We will make use of gpg-preset-passphrase to cache our passphrase for our key. For that we need to make sure gpg-agent allows it.

❯ echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf

Putting it all together

Finding your 1Password entry

I will assume you have a 1Password entry storing your GPG key passphrase, with the name GPG passphrase.

❯ op get item "GPG passphrase" | jq ".uuid"
"vmgevmdnbbuui3evhksdftjhju"

Getting your GPG key grip

We list our keys and their key grips.

❯ gpg --list-secret-keys --with-keygrip
/home/baptiste/.gnupg/pubring.kbx
---------------------------------
sec   rsa4096 2022-02-09 [SC]
      9BA03414AB56590B6DB5369F0052A8D354A5C655
      Keygrip = 80160C5055DA07978E939C0575A4E8DA0B1ECF27
uid           [ultimate] Baptiste Maingret (Home Desktop-WSL2) <baptiste.maingret@gmail.com>
ssb   rsa4096 2022-02-09 [E]
      Keygrip = C04ACB8C33AAA68943194D7D1A56954BF76B5C2C

Look at the sec block and at the Keygrip entry: 80160C5055DA07978E939C0575A4E8DA0B1ECF27.

Binding the two

We will ask the 1Password to retrieve the password and pass it directly to gpg-preset-passphrase specifying our key grip. Note that gpg-preset-passphrase will read stdin by default.

op get item vmgevmdnbbuui3evhksdftjhju --fields password | /usr/lib/gnupg2/gpg-preset-passphrase --preset 80160C5055DA07978E939C0575A4E8DA0B1ECF27

If you weren’t logged in 1Password, you will be asked to input your password.

Running at login

I am using zsh as a shell, so I will add the following to my ~/.zshrc but should be able to do the same with ~/.bashrc for instance. Note that if you are using powerlevel10k, you will need to put the following before the instant-prompt configuration.

function gpg_cache () {
        gpg-connect-agent /bye &> /dev/null # 1
        eval $(op signin my) # 2
        op get item vmgevmdnbbuui3evhksdftjhju --fields password | /usr/lib/gnupg2/gpg-preset-passphrase --preset 80160C5055DA07978E939C0575A4E8DA0B1ECF27 # 3
}
gpg_cache # 4
  1. gpg-agent is automatically started when required, however since gpg is not used in this but we still require gpg-agent we need to make sure it is started. This is the best way I found to achieve it.
  2. Login in 1Password.
  3. Using our one-liner to retrieve the passphrase and cache it.
  4. Calling our beautiful function.

N.B. This will require you to log in each time you start a session. You could also simply remove the call to gpg_cache, and call it from your terminal.

Testing it

Go in one of your git repository, and let’s create a branch and try this out.

❯ git checkout -b signing
Switched to a new branch 'signing'

❯ touch dirty

❯ git add dirty

❯ git commit -m "Trying signing"
[signing 1426360] Trying signing
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 chapter-2/dirty

❯ git log --show-signature -1
commit 1426360d301b88036feef02e00044e6ca62a9fd3 (HEAD -> signing)
gpg: Signature made Tue Feb 15 21:46:51 2022 CET
gpg:                using RSA key 9BA03414AB56590B6DB5369F0052A8D354A5C655
gpg: Good signature from "Baptiste Maingret (Home Desktop-WSL2) <baptiste.maingret@gmail.com>" [ultimate]
Author: Baptiste Maingret <baptiste.maingret@gmail.com>
Date:   Tue Feb 15 21:46:51 2022 +0100

    Trying signing

Remove our dirty work.

❯ git reset HEAD^

❯ rm dirty

❯ git checkout main
Switched to branch 'main'

❯ git branch -D signing

Sources