If you have a GPG key, it makes sense to also use it for SSH authentication rather than generating a separate key. Since GnuPG 2.1 this has become much easier, and whilst there are some good tutorials out there, some are out of date. The basic idea is that instead of using
ssh-agent for SSH authentication, we’ll use
gpg-agent. I mainly used bootc’s wiki page and the notes on incenp.org, changing a few things in search of a cross-platform solution for macOS 10.12 and Debian 9 so that I have a unified set of config files that can be synced using
If you don’t already have a GPG key/subkey with the
[A] (authenticate) capability, you’ll need to generate one first. I won’t describe this process as there are plenty of blog posts out there that do, but in brief I would recommend creating a non-expiring master key with only the
[C] (certify) capability – perhaps keeping this offline – and expiring subkeys for each other capability, as described in this post. Note however that since GnuPG 2.1, you can delete the private part of your master key by deleting the appropriate file (named by keygrip, which you can obtain using
gpg -K --with-keygrip) in
~/.gnupg/private-keys-v1.d so you shouldn’t need to
--export-secret-subkeys and re-import them.
Once you have your GPG key, the output from
gpg -K should look something like the following. Note the
[A] showing that one of our subkeys has the authenticate capability. It’s this subkey that we’ll use for SSH authentication.
sec rsa2048 2018-08-05 [C] 52FEC9F2D4FE99296D1EF4BF1EB7772A98CC62BD uid [ultimate] Anne Example <email@example.com> ssb rsa2048 2018-08-05 [S] ssb rsa2048 2018-08-05 [E] ssb rsa2048 2018-08-05 [A]
First we need to add the following to
~/.gnupg/gpg-agent.conf to enable SSH support in
Next we’ll add the keygrip of the authentication subkey to the
~/.gnupg/sshcontrol file. This tells
gpg-agent that we want to use this particular key for SSH authentication. We can find the keygrip using
gpg -K --with-keygrip and looking for the keygrip associated with the authentication subkey marked
sec rsa2048 2018-08-05 [C] 52FEC9F2D4FE99296D1EF4BF1EB7772A98CC62BD Keygrip = E11D971C7466E818F396867353421EB79BEBF028 uid [ultimate] Anne Example <firstname.lastname@example.org> ssb rsa2048 2018-08-05 [S] Keygrip = 543BEDBDF3D949044EF0C48181BE7C615715F00E ssb rsa2048 2018-08-05 [E] Keygrip = 80B66EE412ADFE27371A03A1CB2013574707A8F8 ssb rsa2048 2018-08-05 [A] Keygrip = 8FFC951FB9BA2A55A1E26C917DC069EC166D7474
In this case the keygrip is
8FFC951FB9BA2A55A1E26C917DC069EC166D7474, which we add to the file
Next we need to add a few commands to our shell startup script. If you use
bash, add the following into
~/.bash_profile. I use
zsh with oh my zsh, so I added the following to a script in
~/.oh-my-zsh/custom/. These ensure that we are using
gpg-agent’s socket rather than
ssh-agent’s and that
gpg-agent runs when your shell starts.
export GPG_TTY=$(tty) export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) gpgconf --launch gpg-agent
At this point it’s a good idea to restart your shell and run
ssh-add -l. If all is well you should see your key listed, for example:
2048 SHA256:0AJnONdvBRmCIvsIvNsL+/of4uW40NJHZsGytyLDPGQ (none) (RSA)
Now we can export the public key in OpenSSH format. Running
gpg --export-ssh-key email@example.com (replacing
firstname.lastname@example.org with the email address associated with your key) gives the following output, which you should add to
~/.ssh/authorized_keys on the server to which you’re connecting.
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDiIPt7la51CBKTkUgYoq307LgXR6FFsLLaveaiYOtszaf8+ilAT31ywHh8rYOFHtNylTeGCzBT8DWOw1ScwCfuQC/2RtL3WcnNFANnarju9DvA9cqEKkwsZiB92elwnfx3f343lDW7hzvTkEuNAFyPOF4BEWG39TUCcAPCRBeiBa31DPJHfT3l2juLblvH2kOa+bLRGK8ppzb8bWS2O6fKn+QQq5EJpD030YutKsIA0Hq7AIiD72xSJGpttVEXWpNGJHGIpUmy8toWw8QrmXMzqx6lUpwrir+mmXpeMn0nbxOfbxxjmYbX9rhDrnXXegVNmMqVN+dCneVTFGsquw5r openpgp:0x7B4D1004
If you have any questions or suggestions, why not get in touch with me on Twitter?