This project defines an SSH Agent specifically tailored for use with YubiKeys.
The canonical home for this project is https://github.com/indygreg/yubikey-ssh-agent.
The agent is only well tested on macOS. It may work on Linux, but that's not the focus of development at the moment.
Obtain a pre-built release from https://github.com/indygreg/yubikey-ssh-agent/releases
or compile your own via cargo build
.
Extract the zip file and drag the YubiKey SSH Agent
application
to your Applications
folder in Finder.
Launch the application by double clicking or running
open "/Applications/YubiKey SSH Agent.app"
from the terminal.
You should see a key/lock appear in your system tray at the top of
the screen.
Then, tell SSH how to use it:
$ export SSH_AUTH_SOCK="~/Library/Application Support/com.gregoryszorc.yubikey-ssh-agent/agent.sock"
To make this change permanent, you'll want something like this at the
top of your ~/.ssh/config
:
Host *
IdentityAgent "~/Library/Application Support/com.gregoryszorc.yubikey-ssh-agent/agent.sock"
Then perform an SSH operation needing the private key on your YubiKey:
$ ssh git@github.com
The application does not yet persist across logouts or restarts. You will need to launch the application whenever you log in. This will be fixed in a future release.
The yubikey-ssh-agent
process provides a minimal SSH agent daemon
that interfaces directly with attached YubiKeys to service requests
for public key lookups and cryptographic signing operations.
The process provides a minimal GUI displaying current state and provides a mechanism for inputting the PIN to unlock the YubiKey.
This tool was born because out of the author's frustration with the user
experience when using YubiKeys with OpenSSH using the default OpenSSH
agent (ssh-agent
) and libykcs11
.
When you use the default OpenSSH SSH agent + libykcs11
:
ssh-agent
spawns assh-pkcs11-helper
process.ssh-pkcs11-helper
loadslibykcs11.{so,dylib,dll}
.- When
ssh-agent
receives a message requesting interfacing with the YubiKey, it calls into APIs inlibykcs11
, which speaks to the YubiKey. - Results from
libykcs11
are relayed back tossh
.
A common problem is that libykcs11
will lose contact with the YubiKey
or your cached PIN expires due to a timeout. What happens in these
scenarios is ssh-agent
thinks that no YubiKey keys are available
and tells ssh
there are no keys. ssh
summarily tries to
authenticate without knowledge of the YubiKey keys. And this often
fails with a Permission denied
message because the client didn't
actually present any public keys!
Or a variant of this is that ssh-agent
advertises the YubiKey-hosted
key but when it attempts to use the key it fails because the YubiKey is
locked (a PIN is required). This also often materializes as a nebulous
and hard-to-debug Permission denied
error.
Unlike the default ssh-agent
+ libykcs11
behavior, this agent
won't fail SSH client operations because the YubiKey is locked, the agent
lost a connection with the YubiKey, or the agent's cached PIN has expired.
Instead, this agent recognizes when a key is locked and prompts the user
to unlock it, before failing the SSH operation.
This SSH agent makes the assumption that the YubiKey is the provider of SSH keys. Therefore, when there is a request for available keys or a signature request, it can be very vocal about raising an error (through its own GUI) when user interaction is needed. For example, if SSH wants to perform a cryptographic signature but the YubiKey is locked, this agent will open a modal window requesting the YubiKey PIN and the SSH agent will wait for you to unlock the YubiKey before failing the SSH attempt.
This agent doesn't support adding keys. This agent doesn't (yet) support caching the YubiKey PIN or management key.
There are no secrets lingering in memory that can easily be extracted by a user on the same machine. (If someone accesses the process at just the right time they could acquire the PIN, however.)
The main threat model for this SSH agent is an unwanted client requesting signing operations. This threat model exists for all SSH agent implementations. For the ultra paranoid, you'll want to set a PIN protection policy on the YubiKey to require a PIN or touch for every operation. Without such a policy, multiple signing operations may be performed from a single unlock/touch and anyone with access to the SSH agent could effectively use the private key on the YubiKey.
This project is still very alpha. The graphical UI in particular is very crude and in need of a lot of work.
Please file issues or just contribute pull requests to improve things.
Only macOS is well tested. Windows doesn't currently build due to https://github.com/sekey/ssh-agent.rs not compiling on Windows (this is a very fixable problem).
macOS has an SSH agent built-in and will set SSH_AGENT_SOCK
automatically
to a value like SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.{random}/Listeners
.
Stick with Security: YubiKey, SSH, GnuPG, macOS has a good overview of the problem and how to work around it.
Essentially, the system built-in
/System/Library/LaunchAgents/com.openssh.ssh-agent.plist
will launch
ssh-agent
and set SSH_AUTH_SOCK
to point to its socket.
You can't edit this file with system integrity protection enabled. So a
workaround is to create your own plists for use with launchd/launchctl
to spawn this agent and symlink over SSH_AUTH_SOCK
.
Some day we'll likely streamline this procedure to enable people to easily
replace SSH_AUTH_SOCK
so SSH clients never use the system default
agent.