About a year ago I bought a YubiKey Nano to use as a hardware token via the emerging FIDO protocol and for OTP. For some time I’ve been aware that it’s possible to keep a PGP keypair on the key and use it for signing and authentication for git. Today I decided to finally set that up. Since this process proved to be a bit confusing I figured I would write it up.
I did this with my YubiKey Nano, but I believe it will work with other models as long as they support OpenPGP. I’m using macOS for this and to work with PGP you need GPG Tools so go install that first. After installing it if you insert your YubiKey and run
gpgp --card-status you should see output like this:
Generating a key
From my research you can chose to generate a PGP key on your own machine and move it to the YubiKey or you can use the built in support to generate the key on the YubiKey itself. This way the key never exists on your machine. To generate the key run
gpg --edit-card at the prompt enter
admin and then
generate. During this process you’ll be prompted to set two PIN codes, one for the key and another that acts as an Admin PIN. The defaults are
During this part I had a lot of problems with errors complaining about broken pipes or missing files. I did a few things and eventually managed to fix this. The steps I took was disabling CCID support via the the Yubikey Manager and then turning it back on. I also restarted my Macbook and killed
After you have successfully generated a key it should show up when you run
gpg --list-keys with an output similar to this:
You can export the RSA public key by running
gpg --export-ssh-key "<name>" > ~/.ssh/yubi_key.pub where
<name> is the name you gave when generating the key. This key is what you want to add to GitHub/GitLab and to
~/.ssh/authorized_keys on any remotes systems you wish to access.
Using gpg-agent for SSH authentication
gpg-agent utility can be configured to take the place of
ssh-agent on your system. When you need to log in to a remote server or push to a git remote this agent provides authentication based on a RSA key pair stored on the YubiKey. At this point I had issues because a lot of answers and guides on the internet are outdated and talk about options that have been deprecated. To get
gpg-agent working you need to create two files
The key thing here is
enable-ssh-support which ensures that the
gpg-agent can act as a
pinentry-program is shipped with
gpg-tools and is used to prompt for the PIN when first using the RSA key in a session.
You can find your key id in
gpg --list-keys, it is the long string of digits and letters on the second row.
Making it all work
After getting this far you just need to ensure that
ssh-agent is not interfering with your setup by setting
SSH_AUTH_SOCK in your
.zshrc. You also need to ensure that
gpg-agent is running. This used to be more complex, but since GPG 2.1.0 there’s a handy tool called
gpgconf that can help.
gpgconf --launch gpg-agent will ensure the
gpg-agent is running.
Given that you have done everything correctly you should now be able to run
ssh-add -L and you should be able to use SSH with the keys stored on your YubiKey. If you remove the YubiKey from the computer you can no longer use the keys on the device as they are stored safely on the key itself.
The YubiKey contains both a SSH key pair and a PGP master key that can be used for sining. You can turn on signing for git commmits by finding your key id with
gpg --list-secret-keys --keyid-format LONG and looking for the id after
rsa2048/XXXXXXXXX then run
git config --global user.signingkey <key-id>. Now you can sign commits with
git commit -S or if you want all commits to be signed set
git config --global commit.gpgSign true. To ensure GitHub recognises your commits as signed you need to add the output of
gpg --armor --export <key-id> to your GitHub Settings.
Uploading the key to key servers
The public key cannot be extracted from the Yubikey so you need to ensure you can still access it later. You can export it as above and keep that armored version around or better yet upload the key to a key server with
gpg --send-keys <key-id>. This way you can just download the public key from the network of key servers on a new computer and insert your Yubikey with the matching private key.
The details of this setup are available in my dotfiles repository in these three commits: