Table of Contents
Secure Shell, Better known as SSH, is one of the most used tools to remotely manage servers. It allows developers and sysadmins around the world to login to a remote server as if they were there; however, as with any remote technology, there are security measures used to authenticate the user.
For anyone who as used SSH before, you probably know that there are two ways to authenticate the user:
- A password (very insecure and not recommended)
- A SSH public-private key pair
ssh-agent to manage ssh keys. On some systems,
ssh-agent isn’t used and SSH just directly serves identity files to the server.
PGP uses a very similar public-private key pair system, and is often used for various purposes. I won’t get into all the amazing ways PGP keys can be used (if you’re reading this, you probably already know some); however, it’s important to point out the different type of keys you can have:
- Certification key [C]
- Encryption key [E]
- Signing key [S]
- Authentication key [A]
Each one of these key types are used in different applications, but we’ll focus on the authentication key. If you don’t already have an authentication sub-key, you should generate one1.
We can ultimately use the PGP authentication key to replace our SSH keys. By replacing
gpg-agent we can have SSH use our GPG keys when connecting via SSH.
This is actually a relatively simple setup to get working. We have to:
- Point SSH to use
gpg-agentfor SSH authorization
gpg-agentto serve the correct authentication key to SSH
Configure SSH to use gpg-agent
SSH uses the
SSH_AUTH_SOCK environment variable which points to UNIX socket used by the authentication agent. To get SSH to use
gpg-agent, we just need to have
SSH_AUTH_SOCK point to
Setting this up is rather simple. We can get
gpg-agent’s socket by running:
gpgconf --list-dirs agent-ssh-socket. We will also need to launch
gpg-agent by running:
gpgconf --launch gpg-agent.
To piece this together, add the following to your shell’s startup file2:
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) gpgconf --launch gpg-agent
GPG still needs to be configured to properly serve the key to SSH.
~/.gnupg/gpg-agent.conf to enable SSH support:
echo 'enable-ssh-support' >> ~/.gnupg/gpg-agent.conf
At this point, SSH should be setup to use GPG keys; however, it’s good practice to specify which GPG key should be served. To do this, you have to first get the keygrip3 from your authentication subkey (the one that should be used for SSH).
To get the keygrip run:
gpg -K --with-keygrip which will produce an output with keygrips for your (sub)keys. Find the keygrip that corresponds to your authentication key, which will be shown with
ssb rsa4096 2020-01-01 [A] [expires: 2022-01-01] Keygrip = 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZABCD
Save the keygrip for the authentication key to
$ echo '1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZABCD' >> ~/.gnupg/sshcontrol
Getting Public SSH Key / Concluding notes
Everything should now be setup to authenticate using GPG keys. To get the public key that should be added to any server you wish to connect to, run
gpg --export-ssh-key <user-id> with your email or GPG key fingerprint. This will output a valid SSH public key that can be added to the
authorized_keys on the remote server(s).
sshcontrol file should contain the keys that should be serve by
gpg-agent, but should any need to be disabled in the future, you can prepend the keygrip with an
! mark to disable it.
gpg-agent is invoked (trying to authenticate a SSH session) without a
sshcontrol file, the file will be generated with the following comment:
# List of allowed ssh keys. Only keys present in this file are used # in the SSH protocol. The ssh-add tool may add new entries to this # file to enable them; you may also add them manually. Comment # lines, like this one, as well as empty lines are ignored. Lines do # have a certain length limit but this is not serious limitation as # the format of the entries is fixed and checked by gpg-agent. A # non-comment line starts with optional white spaces, followed by the # keygrip of the key given as 40 hex digits, optionally followed by a # caching TTL in seconds, and another optional field for arbitrary # flags. Prepend the keygrip with an '!' mark to disable it.