gpg for ssh

GPG and SSH keys are not something I ever really paid a huge amount of attention to. I made a GPG key somewhere in 2018, used it for maybe two or three emails, then only ever used it for encrypting my pass store. It didn’t even have an expiry. SSH keys were similar. I made one at my old job for connecting to my first VPS and just used that for everything across several machines. It’s safe to say that I wasn’t particularly conscious of security around them.

Last week one of my partners was showing me how she uses her GPG key to connect to hosts over SSH. She has much more intricate security practices than me, with lots of sub keys and redundancy and a Yubikey and all sorts of things are signed and verified. I understand very little of it but it certainly is impressive. My use case is far more humble however as I have two computers, a phone, and a VPS to worry about, rather than hundreds of machines spread across various organisations.

While working on a related project, I decided that now was as good a time as any to clean up the ancient keys and create a fresh set that I’d treat better, and I decided to have a go at combining the SSH key into the GPG key so I only had the one to keep track of and because it sounded cool. So:

# generate a new key (RSA, max size, 1y validity, etc.)
gpg --full-generate-key
# reencrypt my password store with the new key
pass init $key_id

For SSH, we want a sub key that is usable for authentication only (source):

# RSA key, max size, use the same expiration date as the main key
gpg --expert --edit-key $key_id
gpg> addkey
# export the public SSH key (for putting in ~/.ssh/authorized_keys)
gpg --export-ssh-key $key_id > gpg_rsa.pub

Now, ssh-agent doesn’t look at GPG keys so it’s not going to be of any use here. Instead, we want to make ssh talk to our gpg-agent instead as it can emulate an OpenSSH agent provided the right environment variables are set (source):

# in my fish config (adjust syntax for use in e.g. bash)
set -e SSH_AGENT_PID
set -x SSH_AUTH_SOCK (gpgconf --list-dirs agent-ssh-socket)
# so gpg-agent knows in what tty to prompt for key passwords
set -x GPG_TTY (tty)
gpg-connect-agent updatestartuptty /bye > /dev/null

That last command can also be added to your SSH config so it’s updated whenever you try to SSH from different terminals:

Match host * exec "gpg-connect-agent updatestartuptty /bye"

Lastly, the ‘keygrip’ of your authentication key needs to be added to ~/.gnupg/sshcontrol so that gpg-agent knows to use it for SSH connections:

gpg --list-keys --with-keygrip

The ‘keygrip’ value just needs to be added by itself as one line in the file for it to work.

Disable ssh-agent however you had been running it and (probably) reboot and now when you SSH to a host you should see the prompt for the password for the GPG key before connecting!