What you need
- OpenSSH 8.2 or later on both sides. That release added the
ed25519-skandecdsa-skkey types. Check the client and the server withssh -V.verify-requiredneeds 8.4. - A key that supports Ed25519. It is optional in the FIDO standard. Yubico says YubiKeys need firmware 5.2.3 or newer. On older ones, use
-t ecdsa-sk. - An OpenSSH build with FIDO support. See the next section if you use a Mac.
To see if a server will accept these keys, run this on the server and look for sk-ssh-ed25519@openssh.com:
sudo sshd -T | grep -i pubkeyacceptedalgorithms
On macOS, the built-in ssh is not enough
The ssh-keygen that comes with macOS gave us this:
No FIDO SecurityKeyProvider specified
Key enrollment failed: invalid format
The Homebrew build of OpenSSH depends on libfido2, which provides this support. Install it and check that your shell finds that version first:
brew install openssh
which ssh-keygen
Create the key
ssh-keygen -t ed25519-sk -O verify-required -C "you@laptop"
Touch the key when it blinks, and enter its PIN if asked. You get two files:
~/.ssh/id_ed25519_sk: the handle. It looks like a private key but holds only a reference. It is useless without the hardware key.~/.ssh/id_ed25519_sk.pub: the public key.
If no key is plugged in, or the system cannot see it, you get:
Key enrollment failed: device not found
Install it and log in
ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub user@server
ssh -i ~/.ssh/id_ed25519_sk user@server
The line in authorized_keys works like any other, but its type is sk-ssh-ed25519@openssh.com.
The options that matter
| Option | What it does |
|---|---|
-O verify-required | Every signature needs user verification, usually the PIN, as well as a touch. A stolen token alone is then not enough. |
-O resident | Stores the handle on the token, so you can use it from another computer without copying a file. |
-O application=ssh:work | Sets a name for the key. It must begin with ssh:. Useful for keeping several resident keys on one token. |
-O no-touch-required | Signing without a touch. The server must also allow it, so leave it off unless you have a reason. |
Resident or not
| Non-resident (default) | Resident | |
|---|---|---|
| Where the handle lives | In a file on your computer | On the token |
| Use on a new computer | Copy the handle file | Download it from the token |
| A thief needs | The token and the file | The token, and the PIN if you set one |
A resident key is convenient, but anyone holding the token can retrieve the handle, so combine it with a PIN:
ssh-keygen -t ed25519-sk -O resident -O verify-required -C "you@laptop"
On another computer, get the files or load the key directly into the agent:
ssh-keygen -K
ssh-add -K
ssh-keygen -K writes the files into the current directory.
Require a PIN from the server side
A key created without verify-required can still be held to it by the server. Add the option at the start of its line in authorized_keys:
verify-required sk-ssh-ed25519@openssh.com AAAA... you@laptop
Plan for a lost token
If the token is gone, the key is gone. Enroll two tokens, install both public keys on each server, and keep the second one somewhere safe. Keep another way in as well, such as a console from your hosting provider, before you turn off other logins.
Keep the handle files, and a note of which servers each token opens, in one place such as an SSH key manager with an encrypted vault.
Questions
Can the private key be copied off the YubiKey?
No. According to the OpenSSH release notes, the private part of the key is unique to each token and cannot be exported. That is also why you should enroll a second token as a backup.
Do I still need a passphrase?
It is optional. The handle file is not enough without the token, and a PIN with verify-required covers the case of a stolen token. A passphrase on the handle file adds another step if you want one.
Can I use the same YubiKey on several computers?
Yes. With a resident key, run ssh-keygen -K on the new computer to get the files back from the token. With a non-resident key, copy the handle file id_ed25519_sk to the new computer. Either way, each login still needs the token.
Sources
- ssh-keygen(1), FIDO authenticator section
- sshd(8), authorized_keys options
- OpenSSH release notes
- Securing SSH with FIDO2, Yubico
- Homebrew openssh formula