I have been using a Yubico
security token to store my GnuPG
private keys for about a year now. The Yubikey is a powerful security token and
I wanted to make use of it to manage my SSH keys as well. I also recently transitioned
to the newer GnuPG ‘Modern’ 2.1.x
release and there are significant changes to how you would go about using your
GPG keys for SSH. Since I ran into a few issues, and the existing documentation
on the web is somewhat lacking, I thought I would write up some notes documenting
how I did it, and how I solved at least one issue I was having with the interaction
between the the Yubikey and the
gpg-agent on macOS.
# NOTE : Installation of 'pinentry-mac' requires a full Xcode installation. # The command line tools are not sufficient. brew tap homebrew/versions brew install gnupg21 brew install pinentry-mac
Installing GPG keys on Yubikey
Here is a useful site for learning how to add your SSH keys to your Yubikey.
Using GnuPG for SSH Authentication
The following websites offered some useful info when learning about using the Yubikey for SSH.
- https://gnupg.org/faq/whats-new-in-2.1.html (see ‘Auto-start of the gpg-agent’)
Setup GnuPG Agent for SSH
UPDATE : January 15, 2016 : It has been brought to my attention that adding a
keygrip to the
sshcontrol file is not strictly necessary when using a smart-card
like the Yubikey. It is apparently only needed when dealing with keys on disk and
also explains the double entry I was seeing with
ssh-add -l. I have removed the
section about discovering your keygrip ID and adding it to
simplifies this setup a bit.
gpg-agent to start with SSH support in
~/.gnupg/gpg-agent.conf by adding the
enable-ssh-support entry. Here’s
my config (which also makes use of the pinentry-mac package we installed earlier).
default-cache-ttl 900 max-cache-ttl 999999 pinentry-program /usr/local/bin/pinentry-mac enable-ssh-support
Next, configure all of your shell environment to have an appropriate
SSH_AUTH_SOCK environment variable. Here are the relevant lines
~/.zshrc. You’ll want to source your config file or close
and open a new terminal window after this change.
... # GPG 2.1.x SSH support # See : http://incenp.org/notes/2015/gnupg-for-ssh-authentication.html export SSH_AUTH_SOCK=$HOME/.gnupg/S.gpg-agent.ssh ...
Ensure your Yubikey is removed and restart your
then re-insert your Yubikey. Alternatively, run
You may want to also confirm that you no longer have any
ssh-agent is no longer used at all with this setup.
* remove key * /usr/local/bin/gpgconf --kill gpg-agent && /usr/local/bin/gpgconf --launch gpg-agent * insert key *
gpg2 --card-status should display a summary of your Yubikey config
including the keys you have installed on it.
Now you are almost ready to go. Your GPG keys are on your Yubikey, the
is running and ready to support your SSH client, and all that you need to do is
reveal your SSH public key so you can add it to the
authorized_keys file on
your remote server you want to access with SSH.
$ ssh-add -L ssh-rsa AAAAB3Nza+MY_LONG_SSH_PUB_KEY cardno:000600000000
Grab the last line starting with
ssh-rsa and paste
that into the
authorized_keys file on the remote machine you want to SSH to.
This should be one long line and should contain no line breaks.
Here is what the docs say
about the behavior of
gpg-agent in the context of SSH. This is important to understand.
gpg-agent must be running for SSH using GnuPG + Yubikey to work.
Auto-start of the gpg-agent : If the option –enable-ssh-support is used the auto-start mechanism does not work because ssh does not know about this mechanism. Instead it is required that the environment variable SSH_AUTH_SOCK is set to the S.gpg-agent.ssh socket in the GnuPG home directory. Further gpg-agent must be started: Either by using a GnuPG command which implicitly starts gpg-agent or by using gpgconf –launch gpg-agent to explicitly start it if not yet done.
OK, you should be ready to
ssh email@example.com now! Make sure your Yubikey
is inserted and ssh to that host. If all is working right, you should be prompted
for the user PIN for your Yubikey to unlock it, and once you enter that PIN you
should succeed in your ssh login.
UPDATE : January 15, 2016 : I am working through this issue in the gnupg-users mailing list. You can follow along with the discussion thread here. I’ll update this post again if there is a resolution to this issue.
I ran into one major problem with this setup. It seems that if the
is running and you remove your Yubikey and re-insert it, the
no longer recognize that your Yubikey is present and SSH logins won’t work.
Normally this isn’t a problem when just using the Yubikey for GPG keys since
GnuPG will take care of launching the agent as needed. But in the SSH scenario
you want the
gpg-agent to be ready to go for SSH whenever your Yubikey is
The only way I could discover to fix this was to kill and restart
each Yubikey insertion.
gpgconf --kill gpg-agent && gpgconf --launch gpg-agent
Of course this is a PITA. There has to be a better way.
Using controlPlane to restart GnuPG agent after Yubikey removal and insertion
What I wanted, as a workaround to the problem, was to re-start the agent after the
Yubikey is removed, and then once again whenever it is re-inserted. I think this may
be possible using
launchd on macOS, but I settled on using ControlPlane which is
an macOS application that can apply system config, or run arbitrary shell scripts,
in reaction to designated system events. In our case it can be configured to run
a shell script that will re-start
gpg-agent every time a Yubikey is inserted
I added the following shell script (make sure it is
chmod 700) to
#!/bin/bash /usr/local/bin/gpgconf --kill gpg-agent && /usr/local/bin/gpgconf --launch gpg-agent
You can test that this technique will work for you by running that script manually after a removal and re-insertion of the Yubikey. If it does, then you can install ControlPlane to automate it.
Setup a ‘Yubikey’ context. This may not be strictly necessary.
Make sure the ‘Attached USB Device’ checkbox is checked on the Evidence Sources tab.
On the Rules tab click the + to add a rule which is based on the presence of the Yubikey. Make sure the Yubikey is plugged in when you select this tab so its available in the drop-down.
On the Actions tab click the + to add a new Action. Provide the full path to your shell script and be sure to set the context to the name of the context you chose in the first step, no delay, and choose to execute on both arrival and departure of the Yubikey.
And that should do it! When you insert or remove the Yubikey you should see
a notification (and a log entry in the advanced tab of ControlPlane) showing
that the script is getting run. Your
gpg-agent should be getting a new PID
every time you insert the Yubikey.
Know a better way?
Please do let me know and I’ll be sure to try out your ideas and document them here if they improve things.
Now all that is remaining is to migrate that collection of SSH public keys you have now over to your new GPG/SSH key to rule them all. Enjoy!