How To Set Up SSH Keys With YubiKey as two-factor authentication (U2F/FIDO2)

All Linux and Unix servers are managed manually or by automation tools such as Ansible using ssh. For example, say you have a server at Linode or AWS. Then you copy your public ssh key to a remote cloud server. Once copied, you can now login to those servers without a password as long as ssh keys are matched. It is the best practice. Unfortunately, you are not protecting ssh keys stored on a local desktop or dev machine at $HOME/.ssh/ directory. If your keys are stolen, an attacker can get access to all of your cloud servers, including backup servers. To avoid this mess, we can protect our ssh keys stored on local dev/desktop machines using physical security keys such as YubiKey.
How to configure SSH with YubiKey
In both cases, you need to insert your YubiKey (or any FIDO2 compatible hardware key) into a USB port and complete the authentication. In other words, ssh login will not work when malware or attacker has stolen your passphrase and ssh keys as they can not insert YubiKey and press the button on it to complete OTP for ssh keys.

In the corporate environment, we have a bastion host that allows ssh access with Yubikey. It is a special-purpose server on a network specifically designed and configured to withstand attacks. The server generally hosts an sshd process, and all other services are removed. Once logged into bastion host, you can access all other cloud servers easily.

What is a YubiKey?

The YubiKey is a hardware authentication device manufactured by Yubico to protect access to computers, networks, and online services that supports one-time passwords, public-key cryptography, authentication, and the Universal 2nd Factor (U2F) and FIDO2 protocol. See how Yubikey works for more details.

FIDO/U2F OpenSSH support

It would be best to have at least OpenSSH version 8.2 or above installed on both client and server. OpenSSH version 8.2 or above adds support for FIDO/U2F hardware authenticators to OpenSSH. U2F/FIDO are open standards for inexpensive two-factor authentication hardware that are widely used for website authentication. In OpenSSH, FIDO devices are supported by new public key types “ecdsa-sk” and “ed25519-sk”, along with corresponding certificate types.

Linux/Unix/macOS desktop requirements

  1. OpenSSH version 8.2+
  2. Linux/Unix/macOS/*BSD operating system

My ssh client and server set up

Here is what I have on my Linux desktop and server:

# Get my client/desktop side Linux info
ssh -V
lsb_release -a
#
# Get my server side info
#
ssh linode-nixcraft-01 -- lsb_release -a
ssh linode-nixcraft-01 -- dpkg --list | grep openssh-server
VERIFY REQUIRMENTS FOR SSH Keys With 2FA Hardware Key

The absolute minimum requirement is OpenSSH version 8.2 met correctly

Finding YubiKey firmware version

Is YubiKey detected on my Linux? Run:
lsusb | grep Yubico
Here is what I see:

Bus 001 Device 022: ID 1050:0407 Yubico.com Yubikey 4 OTP+U2F+CCID

Now pass the USB ID (1050:0407) as follows to find out other info about the key:

lsusb -d 1050:0407 -v 2>/dev/null
lsusb -d 1050:0407 -v 2>/dev/null | more
# just list the firmware version
lsusb -d 1050:0407 -v 2>/dev/null | grep -i bcddevice

My firmware version:

 bcdDevice            5.12

Creating a new YubiKey U2F/FIDO2 protected ssh key pair

On the desktop (dev) computer, generate a key pair for the protocol as follows. First, insert the YubiKey in USB port and then type:

ssh-keygen -t ecdsa-sk # Older YubiKey firmware
ssh-keygen -t ed25519-sk # YubiKey firmware version 5.2.3+ needed
# For example, set ssh key path (-f) and comment (-C)
ssh-keygen -t ecdsa-sk \
-f ~/.ssh/linode_bastion_host_id_ecdsa_sk \
-C "${USER}@${HOSTNAME}_$(date +'%Y-%d-%m')_YubiKey"
How To Set Up SSH Keys With YubiKey U2F FIDO2 OTP

A note about enrollment error

On older firmware version, you will get an error when your run ssh-keygen -t ed25519-sk command that read as follows when your YubiKey version does not support the type of key:

Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
Key enrollment failed: requested feature not supported

Example for the ed25519-sk ssh key type

My YubiKey firmware version is as follows:
lsusb -d 1050:0407 -v 2>/dev/null | grep -i bcddevice
bcdDevice 5.43

Let us create it:

ssh-keygen -t ed25519-sk \
-f ~/.ssh/AWS_bastion_host_id_ed25519-sk \
-C "${USER}@${HOSTNAME}_$(date +'%Y-%d-%m')_YubiKey"

Sample outputs:

Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/vivek/.ssh/AWS_bastion_host_id_ed25519-sk
Your public key has been saved in /home/vivek/.ssh/AWS_bastion_host_id_ed25519-sk.pub
The key fingerprint is:
SHA256:wseSOr11MY7X030OiOfjRx5mMIwSPt9GL8yMBRqbmy0 vivek@nixcraft-wks01_2021-16-08_YubiKey
The key's randomart image is:
+[ED25519-SK 256]-+
|                 |
|        o .      |
|       . * +     |
|     . oB . *    |
|      = SBoO +   |
|     o +Eo+=Bo*. |
|    o . o.=.=*o.o|
|     . o o o..oo.|
|      .    .oo  .|
+----[SHA256]-----+

Copy and install the public ssh key

Next, you can run the scp/rsync or ssh-copy-id script to copy your public key file to your account on the remote server
ssh-copy-id -i ~/.ssh/linode_bastion_host_id_ecdsa_sk.pub \
vivek@linode-nixcraft-01

For AWS:
ssh-copy-id -i ~/.ssh/AWS_bastion_host_id_ed25519-sk.pub \
vivek@aws-nixcraft-bastion-elb-001

Sample session (you may be promoted for the password):

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/vivek/.ssh/linode_bastion_host_id_ecdsa_sk.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'vivek@linode-nixcraft-01'"
and check to make sure that only the key(s) you wanted were added.

The above command appended the linode_bastion_host_id_ecdsa_sk.pub public key file to the remote ~/.ssh/authorized_keys file on server named linode-nixcraft-01 where you want to login using Yubikey U2F/FIDO2. Make sure update your ~/.ssh/config file:

Host linode-nixcraft-01
	Hostname 1.2.3.4
	User vivek
	IdentityFile ~/.ssh/linode_bastion_host_id_ecdsa_sk

See nixcbz[failed to get contents] - contact @ [email protected] with the url for more info.

Test it

Now try to log in using the key (first insert the Yubikey and then type or hit the Enter key):
ssh -i ~/.ssh/linode_bastion_host_id_ecdsa_sk \
vivek@linode-nixcraft-01

And voila. YubiKey based SSH login will only work as long as you press the button on the Yubikey. You can now remove older keys from your server. See the following man pages using the man command:
man ssh_config
man ssh-keygen
man ssh
man sshd

Should I still put a passphrase on my ssh key?

Yes. I recommend putting a passphrase for all your ssh keys. Thus now you have a passphrase and hardware key as 2FA.

How do I deal with lost or broken Yubikey?

The whole point of Yubikey is to prevent misuse. But it is human nature, and Yubikey might go broken or lost. To avoid such a problem, buy two Yubikeys. Use both keys to generate ssh-key pairs and install both public keys on remote servers. Then you can use the backup key when such a need arises. Apart from two backup keys, always keep verified backups of all critical data, including your private and public ssh keys stored in ~/.ssh/ directory.

Summing up

This quick guide explained how to configure two-factor authentication (2FA) with YubiKeys hardware USB key on ssh sessions to get maximum possible protection for your ssh-keys. Make sure you read our my guides published on nixCraft, such as:

If you have any questions or feedback, feel free to leave a comment.

About the author: Vivek Gite is Editor-in-Chief and the man behind nixCraft and OpensourceFlare ✨. He creates and maintains content on both sites as accurately as possible. Since 2000 Vivek has written over 7k+ posts that have been read many times. He is a die-hard fan of FLOSS and a full-time Linux desktop user since 1996. OpensourceFlare provides in-depth guides about Linux, BSD, programming, and other IT topics for Patreon subscribers without any ads or tracking. Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or weekly email newsletter.

3 comments… add one
  • Johan Dec 12, 2021 @ 9:04

    Would love to read, but despite being a supporter on Patreon, I can’t unlock it. Just keep being returned to the same sneak peek.

    • Joseph Dec 19, 2021 @ 12:34

      same here did u ever unlock it i wish i saw your comment before signing up

Leave a Reply

Your email address will not be published. Required fields are marked *

Use HTML <pre>...</pre> for code samples. All comments must be on the topic, and offtopic comments will be automatically removed.