How To Set Up SSH Keys With YubiKey as 2FA

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.

nixCraft: Privacy First, Reader Supported

  • nixCraft is a one-person operation. I create all the content myself, with no help from AI or ML. I keep the content accurate and up-to-date.
  • Your privacy is my top priority. I don’t track you, show you ads, or spam you with emails. Just pure content in the true spirit of Linux and FLOSS.
  • Fast and clean browsing experience. nixCraft is designed to be fast and easy to use. You won’t have to deal with pop-ups, ads, cookie banners, or other distractions.
  • Support independent content creators. nixCraft is a labor of love, and it’s only possible thanks to the support of our readers. If you enjoy the content, please support us on Patreon or share this page on social media or your blog. Every bit helps.

Join Patreon

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 fetched using the ssh command. For example”
# 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

Finding YubiKey firmware version

Is YubiKey detected on my Linux? Run the lsusb command:
$ 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

click to enlarge

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 using the ssh-keygen command. For instance:
$ 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 command 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 how to use the SSH config file tutorial 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.

Did you notice? ????

nixCraft is ad-free to protect your privacy and security. We rely on reader support to keep the site running. Please consider subscribing to us on Patreon or supporting us with a one-time support through PayPal or purchase official merchandise. Your support will help us cover the costs of hosting, CDN, DNS, and tutorial creation.

Leave a Reply

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