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.
Getting started
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 123456
and 12345678
respectively.
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
gpg-agent
.
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
The 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 ~/.gnupg/gpg-agent.conf
and ~/.gnupg/gpg.conf
.
gpg-agent.conf
The key thing here is enable-ssh-support
which ensures that the gpg-agent
can act as a ssh-agent
. The pinentry-program
is shipped with gpg-tools
and is used to prompt for the PIN when first using the RSA key in a session.
gpg.conf
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 .bashrc
/.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.
Git signing
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.
Final notes
The details of this setup are available in my dotfiles repository in these three commits: