As I continue to learn how to secure my various “things”, I’m getting more and more of a fan of physical two factor authentication that doesn’t involve sending six digit codes over the public SMS network. As such, I’ve been playing around with the YubiKey 5 NFC device, a little USB second factor that costs about $50 US and is really handy.
The first thing I wanted to secure with my YubiKey was logins to my various devices. Long-time readers of this blog know that means I need things to work in Windows, Linux and OpenBSD. I thought it would be helpful to outline below how I did that.
OpenBSD
Now for the fun part. Setting up the YubiKey on OpenBSD! I followed this guide to set things up.
If you intend to use your YubiKey on OpenBSD, you will want to do this first, before anything else. The reason for that is that you will need to capture the private ID and private key for your YubiKey slot which can only be done at the time that you generate it. After it has been written to the key, it can’t be retrieved (otherwise, cloning a YubiKey would be a trivial exercise).
Another downside to the implementation of login_yubikey is that it acts as the sole credential to log you in – in other words, it replaces your password and there is no second factor.
First off, you will want to install the YubiKey personalization app:
$ doas pkg_add yubikey-personalization-gui
The limitation to how login_yubikey is implemented currently (as of 7.3) is that you can only have one key. There is no ability to register a second one. However, you can make a backup of the private identity and secret key at the time you generate them and store them in the same place you keep your backup YubiKey.
So, launch the YubiKey Personalization Tool GUI application and insert your YubiKey that you will be using as your only key for OpenBSD. In the UI, click on Yubico OTP from the upper left-hand menu and press the “Quick” button that shows up on the screen. Uncheck the “Hide values” and copy off to a safe place the Public Identity, Private Identity and Secret Key. Select that slot you want to use (in my case, slot 1) and press the “Write Configuration” button and it should write to your YubiKey.
Now create a file called /var/db/yubikey/user.uid and put your private identity value in there (replacing “user” in the filename with your userid). Put the secret key into one called /var/db/yubikey/user.key (again, replacing “user” with your userid). Set up the right permissions on the two files:
# chown root:auth /var/db/yubikey/*
chmod o-rw /var/db/yubikey/*
Finally, edit the /etc/login.conf file and add ‘yubikey’ at the beginning of the auth-defaults entry like this:
# Default allowed authentication styles
auth-defaults:auth=yubikey,passwd,skey:
Now if you reboot, you will find that your password no longer works. Touching your YubiKey after you insert it, however, should replace your password and log you in just fine. According to a wonderful contributor on DaemonForums.org, there is a challenge-response capability that I might be able to use to meet my 2FA requirement; however, I’ll have to tackle that in another post sometime later.
Windows 11
The first thing I needed to do is to make sure that all of my Windows machines were running local accounts. I’m not a fan of Microsoft’s strong push to force everyone to use a Microsoft cloud login for their local machines. Windows 10 at least allowed you the option to ignore the strong push in the UI to set things up with a Microsoft login. For Windows 11, if that option exists, I cannot find it in the UI so I have to initially set up the machine with a Microsoft cloud authentication and then after the OS install is complete, switch it over to a local account.
By the way, if you are curious about how to switch from a Microsoft account to a local account, you need to bring up the settings pane in the UI, then navigate to “Accounts”. From there, click on “Your info” and select the item under “Account settings”. That will allow you to convert your existing Microsoft account to a local one. Or you can just create a new local account, set it as admin and delete the Microsoft one.
After you have either verified you are running a local account or migrated your account and rebooted / logged back in, you will want to create a second admin account that you can use without a YubiKey to prevent you from locking your keys in the car. While I acknowledge this makes things less secure, I created mine with a 20+ character password and no password recovery questions that make sense to anyone (just gibberish in the answers) and rolled with it. If you are feeling that your threat model wouldn’t support such a “back door”, there is no requirement to create such an account, just be warned that you could potentially lose access if you screw up.
That said, I then logged out of my normal user account and logged into this backup admin account. From there, I installed the “Login Confirmation” application from Yubico and rebooted the machine.
Upon reboot, the login screen looks like you require your YubiKey to log in. Actually, not yet until you configure things. Once you log in, run the “Login Confirmation” application you just installed. I switched to “Advanced configuration” so that I could control the behavior of the application as I set it up. On the next screen, I selected the following options:
- Slot 2
- Use existing secret if configured – generate if not configured
- Generate recovery code (I do this for the first machine I setup and then save it off, after that I don’t generate a new code)
- Create backup device for each user (only do this if you have purchased 2 separate YubiKeys – I have and I keep my backup in a safe / secure location in case I lose the primary)
You then need to pick the accounts you want to secure with your YubiKey(s) (again, I only pick my primary account, not the new admin account I created in case I’m locked out) and click “Next”. You’ll then be prompted to insert your primary YubiKey, then your secondary one. At this point, you should be good to go. I reboot just for grins, and then verify that (1) I cannot log into my primary account unless one of the two YubiKeys is inserted; (2) I can log into my emergency admin account without a YubiKey; and (3) that both YubiKeys work for logging into my primary account.
Linux (Ubuntu)
First things first, we need to add the official PPA for Yubico to apt:
$ sudo add-apt-repository ppa:yubico/stable
$ sudo apt update
Now go ahead and install all of the Yubico software:
$ sudo apt install yubikey-manager yubikey-personalization libpam-yubico libpam-u2f yubikey-manager-qt yubioath-desktop
Next, you will need to set the PIN on your FIDO2 capability on both of your YubiKeys. To do this, run the Yubico Authenticator app and select “YubiKey” from the hamburger menu. Insert your primary YubiKey and scroll down to the Configuration section in the GUI. If you click on the right arrow next to WebAitjm )FIDO2/U2F), you can program the PIN. Do this for your backup key as well.
To associate the U2F key(s) with your Ubuntu account, open terminal and insert your YubiKey:
$ mkdir -p ~/.config/Yubico
$ pamu2fcfg > ~/.config/Yubico/u2f_keys
You will be prompted to enter your PIN that you set above and then when the YubiKey lights up, touch the “y” symbol on the physical key and it will save the information on your account. Now repeat the process with your backup YubiKey:
$ pamu2fcfg -n >> ~/.config/Yubico/u2f_keys
Now, let’s add some additional security by moving the config files to a root-only accessible location and update the configuration for PAM to point to it:
$ sudo mkdir /etc/Yubico
$ sudo mv ~/.config/Yubico/u2f_keys /etc/Yubico/u2f_keys
Now we will need to change a configuration file in /etc/pam.d/sudo and add the following line after the “@include common-auth” line:
auth required pam_u2f.so authfile=/etc/Yubico/u2f_keys
Now, let’s test things to be sure that sudo is working with the YubiKey. To do this, open a fresh terminal window, insert your YubiKey and run “sudo echo test”, you should have to enter your password and then touch the YubiKey’s metal button and it will work. Without the YubiKey inserted, the sudo command (even with your password) should fail.
So now we need to repeat this process with the following files:
runuser /etc/pam.d/runuser
runuser -l /etc/pam.d/runuser-l
su /etc/pam.d/su
sudo -i /etc/pam.d/sudo-i
su -l /etc/pam.d/su-l
Now we need to configure the system to require the YubiKey for login. To do this, we perform the same thing as above but in the /etc/pam.d/gdm-password file. Do this also for the /etc/pam.d/login file if you want to protect console text-based login. Finally, create a log file for the system to use by touching /var/log/pam_u2f.log and add this to the end of the pam_u2f.so lines above that you want to debug:
auth required pam_u2f.so authfile=/etc/Yubico/u2f_keys debug debug_file=/var/log/pam_u2f.log
Reboot your system and you should be pretty much locked down to use the YubiKey for anything important.
LUKS Full Disk Encryption (Ubuntu)
OK, if you really want to take your 2FA to the next level, you can make it so that your YubiKey is required as a second factor to unlock your LUKS-encrypted disk. Not a replacement for your password, but a true second factor that is required in addition to your password in order to unlock the disk. I was able to get this to work by following the instructions in this post as well as the GitHub repo. To summarize, see below.
If you are using your YubiKey for Windows 11 login as I outlined above, your second slot in the key is already in use so DO NOT do what I am about to tell you. If, however, you are not using that second slot for Windows login, you need to install the YubiKey personalization software and then initialize slot 2 (for both your primary and backup YubiKeys if you have two):
$ sudo apt install yubikey-personalization
$ ykpersonalize -2 -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible
Now, with either your existing slot 2 configuration for Windows 11 login, or with the new one that you did above, you will need to enroll your YubiKey to the LUKS slot. Figure out first what your partition name is using the lsblk command. You are looking for a partition labeled as “crypt”. In my case it is /dev/nvme0n1p3 (not the /dev/nvme0n1p3_crypt):
$ sudo apt install yubikey-luks
$ sudo yubikey-luks-enroll -d /dev/nvme0n1p3 -s 1
You will be prompted for a challenge passphrase to use to unlock your drive as the first factor, with the YubiKey being the second factor. Since you are using a higher security (2FA) mechanism to unlock the drive, there is no need for this challenge passphrase to be crazy long. You can use a much longer passphrase for slot 0 to unlock the drive without the YubiKey as a failsafe.
Repeat this in a different slot with your backup YubiKey. If you would like to see which slots are in use in your current LUKS partition, use the command:
$ sudo cryptsetup luksDump /dev/nvme0n1p3
That is also a good way to confirm you have the right partition name.
Now, you will need to update /etc/crypttab to add a keyscript:
cryptroot /dev/nvme0n1p3 none luks,keyscript=/usr/share/yubikey-luks/ykluks-keyscript
After editing the file, you will need to transfer the changes to initramfs:
$ sudo update-initramfs -u
At this point, you should be able to reboot your machine and verify that you can unlock the disk with your original LUKS passphrase (what is now your fallback) as well as your new challenge passphrase and the YubiKey.
If you would like to update your YubiKey challenge passphrase in the future, you simply use the same command you did to set enroll it initially, but append a “-c” to clear out the old LUKS slot:
$ sudo yubikey-luks-enroll -d /dev/nvme0n1p3 -s 1 -c
When you are asked to “Enter any remaining passphrase”, that is where you enter your (hopefully) much longer fallback passphrase that doesn’t require the YubiKey, then you are asked to supply the new passphrase twice.
If you would like to update your fallback passphrase that doesn’t require a YubiKey, you can use the command:
$ sudo cryptsetup luksChangeKey /dev/nvme0n1p3 -S 0
You should be prompted for your old password and the new password twice.
UbuntuOne Single Sign On
For us Ubuntu users, eventually you end up creating an UbuntuOne account for things like access to Launchpad, access to your free UbuntuPro tokens, etc. Part of the setup for this is to supply a second factor for 2FA logins to increase the security of your account. The way I have mine set up, I have added Google Authenticator as one of my additional factors but I’d like to have my YubiKey be my primary second factor with Authenticator as my fallback if I don’t have access to the YubiKey (either primary or secondary)..
To set this up, navigate to https://login.ubuntu.com/ and log into your account. Then navigate to My Account -> Authentication Devices. On that screen you will see that you can “Add a New Authentication Device”. When you click on that, select YubiKey and follow the on-screen instructions. I would recommend doing this with your primary YubiKey as well as your backup one.
GitHub
If you would like to use your YubiKey for a second factor when logging into GitHub, it’s pretty easy to do. Simply log into your GitHub account, click on your picture in the upper right header and select Settings from the dropdown menu. On the settings screen, select “Password and Authentication” to navigate to that settings page. On this page, you will need to enable 2FA if you haven’t already done so. I use Google Authenticator as my fallback 2FA method here as well.
To add your YubiKey(s), click on the “Edit” button next to the “Security Keys” section and press the “Register new security key” button. You will be prompted to name your key (i.e. “Primary YubiKey” or “Secondary YubiKey” are what I used) and then you will be prompted to insert your key and press its metal button. Repeat this process with any additional YubiKey(s) you might have and then you have added this as a second factor for GitHub.
SSH 2FA
Adding a second factor to your SSH key infrastructure is fundamentally a really (did I say really?) good idea. The way you set this up server-side depends on the operating system that is hosting the ssh server. I’ll break it down below:
Ubuntu
I followed the howto on the Yubico site and followed the instructions for the “Non-discoverable” keys which are stated as being higher security than “discoverable” keys. Starting out, I first checked the firmware of your YubiKey as follows:
$ lsusb | grep Yubico
# Get the two 4-digit numbers separated by a colon and use them in place of the xxxx:xxxx below
$ lsusb -d xxxx:xxxx -v 2>/dev/null | grep -i bcddevice
In my case, my firmware was version 5.12. This actually turned out to be 5.1.2 which put me below the minimum firmware version 5.2.3 for the stronger encryption. Also, you can’t update the firmware on your YubiKey – it is set at the factory. Ah well.
Given that, I’ll generate my keypair. On your desktop machine, generated the U2F/FIDO2 protected key pair:
$ ssh-keygen -t ecdsa-sk # Older YubiKey firmware
$ ssh-keygen -t ed25519-sk # Firmware version 5.2.3+
When I ran the top command (because my YubiKey had the older 5.1.2 firmware), I got an error that said “You may need to touch your authenticator to authorize key generation” and yet I was never offered the attempt to do so. Therefore, I added the -vvv switch to the command and saw an error saying that my device “does not support credprot, refusing to create unprotected resident/verify-required key”.
After doing some more digging, I discovered that there is a command I can run to validate the capabilities of my YubiKey:
$ sudo apt install fido2-tools
$ fido2-token -I /dev/hidraw1
What I discovered to my disappointment is that my primary YubiKey (which I have had for several years) does not support the “credProtect” feature (it should show up in extension strings in the output of that command. My new secondary key, however, did. Therefore, I worked using my newer key and placed an order to Yubico for another one to use as my new primary. Sigh… My newer YubiKey also had firmware 5.4.3 so I’ll be able to use the newer crypto. Probably better in the long run.
I chose the filename of “id_primary_yubikey” for my primary key and “id_backup_yubikey” for my backup keys. This generated a pair of files, one without a suffix and the other with a .pub suffix (indicating that it is the public key) for each of my two YubiKeys.
So. We now have a new primary and backup keypair in our local .ssh directory. How do we get this to work on our remote server(s)?
It’s pretty straightforward. Take the contents of the .ssh/id_primary_yubikey.pub file and append it to the ~/.ssh/authorized_keys file on the remote server you are trying to ssh into. Repeat this process with the .ssh/id_backup_yubikey.pub file. Now when you ssh into the remote system using the identity you generated:
$ ssh -i ~/.ssh/id_primary_yubikey user@remote-system
You should notice that the Yubico symbol lights up on your YubiKey asking you to touch it. When you do so, you should be logged into the remote system.
If you would like to add your new identity to your SSH agent:
$ ssh-add ~/.ssh/id_primary_yubikey
Now you should be able to ssh directly into your remote system without having to supply the identity file.
If you still can’t get into the remote system, it is possible that it is not configured to support the sk-ssh-ed25519@openssh.com algorithm. To see what algorithms your remote system accepts, log into it and run the following command:
$ ssh -Q PubkeyAcceptedAlgorithms
Conclusion
Congratulations. You have now YubiKey’ed “All the Things!” Take that secondary YubiKey you bought and lock it in a safe somewhere. Keep the other one with you and you are now more secure than you were when you started.