Fancy Linux Security with YubiKey
At $workplace
, folks with access to sensitive systems and infrastructure are
provided with YubiKeys to be used as a multi-factor authentication mechanism. In
the end, it is even better, as we can authenticate against services and systems
without even needing to enter a username/password combination. The device alone
is enough to bypass the authentication page. But this post is not about what you
can do on the web using YubiKeys. No. I’m more interested on how to leverage the
key to also lock and unlock my workstation based on its presence. The
workstation itself counts with disk encryption and other protections, so those
areas are already covered. But what if I could authenticate sudo
or even
lock/unlock the computer using the key that I already need to have with me at all
times whenever I’m handling anything work-related?
Today we will configure Linux to work with a YubiKey for authenticating sudo
password challenges, and also locking/unlocking the machine depending on the
presence of the key itself!
The Environment
I will be working on a machine running Ubuntu LTS. But should be equivalent in other distros (YMMV). The key is an YubiKey 5C NFC in a keychain form factor.
Hic Sunt Dracones
Throughout this post we will be dealing with PAM. In case PAM sounds like something new, it may be enough to know that it is responsible for handling authentication in Linux. PAM stands for Linux Pluggable Authentication Modules. To quote the project:
PAM provides a way to develop programs that are independent of authentication scheme. These programs need “authentication modules” to be attached to them at run-time in order to work. Which authentication module is to be attached is dependent upon the local system setup and is at the discretion of the local system administrator.
Pretty fancy, eh? Anyway. If you intend to follow along the first precaution you
should take is make sure you don’t get locked out of your system. This can
be simply accomplished by having a spare terminal session as root, so in case
of an emergency, you will be able to rollback the system to an usable state.
Also, please do notice all shell commands here are prefixed with $
: they are
meant to be executed by your non-priviledged account.
Step 1: Installing Dependencies
Of course we will need some extra modules. Fire up a terminal, and sudo apt
install
the following packages:
libpam-yubico yubikey-personalization yubikey-manager
Step 2: Configure the YubiKey
Each YubiKey has two “slots” on its OTP application. The IT department already
configured the first one and tied it to my account, but the second one is empty,
so I’ll use the later. Before continuing, make sure your slot is empty. This can
be done by using ykman
we just installed:
$ ykman otp info
Slot 1: programmed
Slot 2: empty
Empty is good! So let’s use that one. What we want to do here is configure that slot to contain a “Challenge-response” configuration, which is basically what the key already does, but without requiring the key to be touched. This of course is a reductive summary of what the configuration really is, and extensive documentation regarding it can be found on Yubico’s Website.
Now that we ensured our second slot is empty, it is time to configure it.
Doing so is really simple. We want to use ykman
to configure OTP’s chalresp
on slot 2:
$ ykman otp chalresp -g 2
Using a randomly generated key: ...
Program a challenge-response credential in slot 2? [y/N]:
ykman
wants a confirmation that we are sure we want to program slot 2. Hit y
with your favourite finger, and confirm.
Step 3.1: Store the Initial Challenge
The Initial Challenge file contains the expected challenge and response to be obtained in the next authentication round. It will be used by PAM later to assert whether a valid key is connected to the machine. As you may guess, this file contains sensitive information! We will need to store it with care.
First, let’s extract it. For that step, we will need ykpamcfg
:
$ ykpamcfg -2
Directory /home/vitosartori/.yubico created successfully.
Sending 63 bytes HMAC challenge to slot 2
Sending 63 bytes HMAC challenge to slot 2
Stored initial challenge and expected response in '/home/vitosartori/.yubico/challenge-12345678'
That was easy! However, there’s an important information right there: ykpamcfg
said it stored the challenge and expected response in a file. That file is called
challenge-<SERIAL>
, where SERIAL
is the serial of that specific key you are
using. In the example above, the key’s serial is 12345678
. We will need that
later!
Step 3.2: Moving the Initial Challenge to a System Directory
libpam-yubico
will look for that challenge file in a few different
directories, but in order to accomplish our objective, we will need to move it
to a specific one. So let’s do it:
# Create the directory
$ sudo mkdir /var/yubico
# Ensure it belongs to root
$ sudo chown root:root /var/yubico
# And restrict access to it
$ sudo chmod 0700 /var/yubico
Finally, move the generated challenge to the directory we created. I’ll break this into two steps cause the first one requires a bit extra attention:
sudo mv /home/vitosartori/.yubico/challenge-12345678 /var/yubico/vitosartori-12345678
The name of destination file is important! It must comprise your username,
followed by a dash, followed by the key’s serial. Effectively, we must move it
to /var/yubico
and replace the challenge
part of the filename with your
username.
Finally, fix file permissions and ownership:
sudo chown root:root /var/yubico/*
sudo chmod 0600 /var/yubico/*
Step 4: Configuring libpam-yubico
We will now configure Yubico’s PAM to use challenge-response mode, look for
challenges on /var/yubico
, and temporarily enable a debug mode (so we make
sure everything is alright and figure out in case anything goes awry during
authentication tests.)
For this step we will leverage dkpg-reconfigure
to do some magic. To get a
complete list of available options, check yubico-pam’s repository.
This procedure will be performed in two steps, since they require some extra
attention. First, run dpkg-reconfigure
:
$ sudo dpkg-reconfigure libpam-yubico
It will show a dialog explaining operation modes and such. Select the text field and erase all its contents. Then, enter the following parameters:
mode=challenge-responds chalresp_path=/var/yubico debug
Then, confirm the changes. Another dialog will be displayed, asking to select
which behaviours are to be enabled. Look up for the Yubico authentication with
YubiKey
, and make sure it checked, then confirm changes.
Finally, it’s time to just change a small setting. By default, the new PAM
module will be configured as required
, which means it will be the sole
authentication method on the system. This is not what we want; I think having
YubiKey support is interesting, BUT being able to type my long password is also
important. Let’s change this.
Fire up your preferred editor to edit /etc/pam.d/common-auth
. I’ll use vim:
$ sudo vim /etc/pam.d/common-auth
Then, look for a line defining pam_yubico.so
as an authentication module.
It should look like this:
auth required pam_yubico.so mode=challenge-response chalresp_path=/var/yubico debug
Then, replace required
with sufficient
, and save the file.
Step 5: Test
Finally! Ensure your key is still connected to your system, open a new terminal session, and
run sudo -s
:
$ sudo -s
debug: ../pam_yubico.c:838 (parse_cfg): called.
debug: ...lots of
debug: ../pam_yubico.c:1220 (pam_sm_authenticate): done. [success]
# whoami
root
#
If you are now in a root shell, congratulations! It is done! Now disconnect the
key, open a new shell, and try sudo -s
. Authenticate using your password. If
it works, then we are done! There’s just one last step…
Step 6: Disable Debugging
Of course we don’t want that much log whenever we run sudo
. If everything is
as it should be, we don’t need that debug
parameter any longer. Open your
editor on /etc/pam.d/common-auth
, locate the pam_yubico.so
, and remove
the last debug
parameter. Save, and it’s done! Even GNOME’s screen lock works
out of box!