Use GPG for SSH keys
Table of Contents
GPG and gpg-agent are capable to serve GPG authentication subkeys as SSH keys. GPG has infamously unfriendly user interface so here’s hopefully an easy to follow tutorial which explains how to:
- add new SSH key managed by GPG;
- change ssh-agent to gpg-agent and add new SSH keys to it;
- use it in ~/.ssh/config
- copy it to the server’s authorized_keys with ssh-copy-id
New GPG Key
For tutorial completeness sake, let’s create a new GPG key. You can of course skip this step if you already have a key which you’d like to use.
NOTE: In this article I’m using gpg2
command, but you can change
it to ordinary gpg
.
To generate a new GPG key, you should run:
$ gpg2 --full-generate-key
and answer some questions which GPG asks you (like your name or e-mail address which should be associated with the new key). You can safely use default answers for most of them. Consider using longer key length than the suggested default though (for example 4096 bytes).
New Subkey
First we need to add a new authentication subkey to the existing GPG key. We do it by entering an interactive GPG command line:
$ gpg --expert --edit-key <key id>
(... output ...)
gpg> addkey
Please select what kind of key you want:
(...)
(8) RSA (set your own capabilities)
(...)
From here we choose a subkey type to which we can set our own capabilities.
In this case I chose RSA (set your own capabilities). We should change it
to leave only Authenticate capability. New subkeys have Sign and
Encrypt capabilities set by default so we have to choose s
and e
(to
disable them) and then a
(to enable Authenticate).
We confirm selctions, then choose the subkey length (which is by default the
same as length of our primary key), key expiry date (0 by default, meaning no
expiry date) and confirm everything with save
command.
Let’s confirm that new subkey was added:
$ gpg2 --list-keys --with-keygrip --with-subkey-fingerprint
and note subkey’s keygrip and fingerprint, we’ll need it later.
This way we can add as many authentication keys as we want. Repeat this step if you’d like to use different SSH keys for different services.
Enabling GPG Agent
We can’t use ordinary ssh-agent with keys managed by GPG. We must use
gpg-agent with SSH support enabled. To enable it, we add enable-ssh-support
line to ~/.gnupg/gpg-agent.conf. While we’re here, it’s also worthy to
change the default times for keys caching (i.e. time in which gpg-agent won’t
ask as for the password). After all our changes it should look more-less like
this:
enable-ssh-support
default-cache-ttl 180800
max-cache-ttl 180800
default-cache-ttl-ssh 180800
max-cache-ttl-ssh 180800
Next, we must actually run gpg-agent:
$ unset SSH_AGENT_PID
$ agent_sock=$(gpgconf --list-dirs agent-socket)
$ export GPG_AGENT_INFO=${agent_sock}:0:1
$ export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
$ gpg-connect-agent updatestartuptty /bye
It’s best to add these lines to your session startup scripts (like ~/.xsessionrc). If you’re using Debian, there’s a good chance that your OS already does this part somewhere in /etc/X11/Xsession.d. If you’re using Wayland, run them before your compositor starts.
Adding Key to GPG Agent
GPG Agent automatically manages keys listed in ~/.gnupg/sshcontrol,
whithout need to add them with ssh-add. You need to add the keygrip of
your key here (see gpg2 --list-keys
from New Subkey step).
If you still want to use ordinary SSH keys along the GPG ones, you should add them once with ssh-add, which should automatically update sshcontrol file with their keygrips.
Next, we should restart gpg-agent to apply the changes, for example by
running gpg-connect-agent /bye
, or systemctl restart gpg-agent.service
gpg-agent.socket
, if you happen to manage gpg-agent with systemd.
Exporting Public Keys
Some tools and configuration files, like ~/.ssh/config, require ordinary
public keys. It’s possible to get them with gpg2 --export-ssh-key <key id> >
~/.ssh/gpg.pub
.
But here’s a catch: --export-ssh-key
exports only the last SSH key. To
export a specific key, we must pass its fingerprint, followed by an
exclamation mark (see gpg2 --list-keys
from New Subkey step
on how to get it):
$ gpg2 --export-ssh-key <fingerprint1>! > ~/.ssh/key1.pub
$ gpg2 --export-ssh-key <fingerprint2>! > ~/.ssh/key2.pub
You can confirm that correct key was exported by checking its name (at the end): openpgp:0x<fingerprint-end>, where fingerprint-end arejthe last 8 hexadecimal numbers of full subkey’s fingerprint.
Now we can use it in ~/.ssh/config:
Host localhost
Hostname 127.0.0.1
IdentityFile ~/.ssh/gpg.pub
IdentitiesOnly yes
or we can send it to the remote server with ssh-copy-id:
$ ssh-copy-id -f -i ~/.ssh/gpg.pub ssh.example.com
Notice that we must use -f
flag, because we don’t have a private key
exported. This can result in more than one copy of the key being installed on
the remote system (if you run ssh-copy-id more than once), but it shouldn’t
be a problem and you can always edit authorized_keys manually.
Good job, we have configured GPG to handle our SSH needs! Now it’s time for the hardest part: replacing all SSH keys for all online services.