YubiKey Multi-Factor Authentication on Ubuntu Server 20.04 - Part 1

TLDR: Setting up YubiKey OTP as a second-factor (password + OTP) for authentication on Ubuntu 20.04 using PAM.
 
This is the first post on a series where I want to explore various authentication mechanisms for Linux, and their integration with YubiKeys. I found that the resources already available on the internet were lacking, incomplete or outdated, so I decided to write my own.
 
I have multiple systems on my network, and managing credentials is a huge pain. The end goal will be to explore ways to have a central authentication server which supports YubiKeys.

I strongly suggest testing the setup first using disposable servers first. I did not follow this suggestion and ended up locking myself out of one of my servers! It is also a good idea to have multiple terminals open, in case you make a change and it does not work, you can use the second one to revert back.

Requirements

  1. Server running Ubuntu Server 20.04.2. I am using a fully-updated server as of the time of writing
  2. Yubico API ID+Secret key. You can get those here
  3. YubiKey Token IDs. These are simply the first 12 characters of the OTP code

Installing and configuring Yubico's PAM module

First, let's install the PAM module from Yubico

$ sudo apt install libpam-yubico
 
For reference, this is the version I installed
 
$ sudo apt list | grep yubico | grep pam
libpam-yubico/focal,now 2.26-1 amd64 [installed]

Configuring your YubiKeys

First we need to associate our yubikeys with the given user (Source 1). I am going to use the central configuration file based on the Yubico documentation.

Use whichever editor you prefer. I use vim, but a lot of people like nano.

$ sudo vim /etc/yubikey_mappings
 
Add the following, based on your user(s) and YubiKey(s):
 
<username>:<YubiKey Token ID1>:<YubiKey Token ID2>...
 
In my case I have 2 YubiKeys so the file looks as follows (not my actual YubiKey IDs). See the requirements or Source 1 if you don't know what these Token IDs are.

$ sudo cat /etc/yubikey_mappings
radius:ccccccjkasdh:ccccccjmershn

Configuring PAM

Now we can tell ubuntu we want to use our YubiKey as an authentication mechanism.

$ sudo pam-auth-update
 
In here we will just select The Yubico option and press enter

This modifies the required authentication config file, but we still need to add the Yubico Client ID and Token. We do this by modifying /etc/pam.d/common-auth
 
$ sudo grep yubico /etc/pam.d/common-auth
auth    required        pam_yubico.so mode=client try_first_pass id=N key=K
 
Change N and K to their real values (N= Client ID, K= Secret Key from requirement 2). Then we need to add the yubikey mapping file - This should not be needed if you are using a per-user configuration.
 
$ sudo vim /etc/pam.d/common-auth
 
This is what this line should look like after the fact (not my real id and key):

$ sudo grep yubico /etc/pam.d/common-auth
auth    required        pam_yubico.so mode=client try_first_pass id=12345 key=VvAaKkTt913rjsBASQI= authfile=/etc/yubikey_mapping

Testing

Let's verify that everything is working as expected. We can start by checking SSH. The tricky bit here is that we need to provide the password and the OTP at the same time. This is done by typing your password and then getting YubiKey OTP. We will let the YubiKey press <Enter> for us. The password will look something like this superSecretccccccjkasdh....
 
radius@radius1:~$ ssh radius@radius1
radius@radius1's password:
Last login: Sun Jul 11 14:10:57 2021 from 127.0.0.1
radius@radius1:~$

If we just use the password or the OTP, it should fail.

radius@radius1:~$ ssh radius@radius1
radius@radius1's password:
Permission denied, please try again.
 
This will also affect sudo. This is much nicer since you are asked for the OTP and password separately:
 


Note: At this point you can simply comment-out the pam_yubico.so line in common-auth, that will bring you back to your default configuration, removing the YubiKey requirement.

Comments