Yubikey is currently the de facto device for U2F authentication. It enables adding an extra layer of security on top of SSH, system login, signing GPG keys, and so on. It is also compatible with several other authentication methods, such as WebAuthn and PAM.
This post will show how to leverage your Yubikey for unlocking the system lock-screen, both with and without using a password. It will then delve into how to automatically lock the screen when the Yubikey is unplugged.
To achieve logins with Yubikeys we require a PAM configuration. PAM or Pluggable Authentication Modules define the authentication flow for common Linux utilities, such as sudo
, su
, and passwd
. We will override the default authentication flow for the xlock lock manager to allow logins with Yubikey.
Note: The above process should be similar across most lock managers, such as
i3lock
orxscreensaver
.
Creating a PAM configuration
We shall first replicate the default authentication provided with xlock using PAM. With this configuration the user should only be able to log in with their password.
All PAM configuration files lie under the /etc/pam.d/
directory. We create a file named xlock
which replicates the default authentication:
$ cat /etc/pam.d/xlock
#%PAM-1.0
auth include system-auth
Note: For the above configuration file to take effect the tool (
xlock
) must be PAM compatible. We can confirm thatxlock
is PAM compatible by inspecting the output ofldd /usr/bin/xlock | grep libpam.so
.
The first comment line indicates the PAM version. The lines that follow define the authentication flow:
auth
is the module interface responsible for verifying the user’s password.include
is the PAM control flag which includes thesystem-auth
configuration file (this file defines the default authentication flow). This flag can also be used to load modules, as we shall see later.
Note: There is an excellent documentation provided by RedHat on PAM configuration files.
Supporting Yubikey logins
We shall now add Yubikey login functionality to our PAM configuration, but we first need to install the Yubico module for PAM and set it up.
Yubico, the company behind Yubikeys, exposes the pam_yubico.so module which can be used for Yubikey authentication.
It provides two authentication mechanisms, the client
mode and the challenge-response
mode. The client
mode sends a request to the Yubico server for verifying the user’s OTP, and requires an active Internet connection for the user to login. As this is inconvenient we shall only explore the challenge-response
mode in this post.
Before proceeding with the configuration the pam_yubico
package must be installed manually. This package is easily available across most Linux distributions. On Arch Linux it can be installed with:
$ pacman -S yubico-pam
We next add Yubikey mappings before setting the challenge-response credential.
Warning: It is recommended that you use a secondary account to perform the next steps as there is a risk of permanently locking your account (in case of PAM misconfiguration).
Adding mappings
Each Yubikey must be paired with a unique public ID which the pam_yubico
module uses to uniquely identify the user. The public ID consists of the first 12 characters extracted from the OTP token.
To obtain your Yubikey’s public ID open up your shell and press the Yubikey button. You will see a similar output as below:
vvctffbvkhdnliklfhbbfiecudthfvrvuhnhtirehidr
Now copy take the first 12 characters (vvctffbvkhdn
) and add them to a file named yubikey_mappings
in the /etc/
directory, along with your username. In our case this will be:
$ cat /etc/yubikey_mappings
adeel:vvctffbvkhdn
Note: This file also allows specifying multiple Yubikey mappings, each separated by a new line.
Setting the challenge response credential
Yubikey needs to somehow verify the generated OTP (One Time Password) when it tries to authenticate the user. It does so by using the challenge-response
mode.
To set up the challenge-response
mode, we first need to install the Yubikey manager tool called ykman
. On Arch Linux it can be installed with:
$ pacman -S yubikey-manger
The ykman
tool will generate a secret credential and store it in a local file. Whenever the user tries to login with xlock
, the pam_yubico
module will verify the generated OTP against the stored credential.
The challenge response credential can be set on slot 2 of the Yubikey with:
$ ykman otp chalresp --generate 2
Using a randomly generated key: 29eb38b6f50b246c46f954af9710a77c78792114
Program a challenge-response credential in slot 2? [y/N]: y
Warning: Ensure that the slot you’re writing the data to doesn’t already contain any credential, as it might not be recoverable!
After the challenge-response
credential is set it needs to be written to a local file which will be later read by pam_yubico
.
Yubico provides another tool called ykpamcfg
(which should be bundled with the yubikey-manger
package) to write this file to disk. It takes the Yubikey slot number as its parameter and writes the secret to a file:
$ ykpamcfg -2
Stored initial challenge and expected response in '/home/adeel/.yubico/challenge-<Serial ID>'.
Updating the Linux PAM configuration
We shall now update the /etc/pam.d/xlock
file and add the Yubico PAM at the very beginning.
$ cat /etc/pam.d/xlock
#%PAM-1.0
auth sufficient pam_yubico.so debug mode=challenge-response authfile=/etc/yubikey_mappings
auth include system-auth
We pass three parameters to the pam_yubico.so
module:
debug
prints all the authentication steps to the console when the ‘Enter’ key is pressed.mode
specifies which mode the module will use for authentication (challenge-response
orclient
).authfile
points to the credential file written by theykpamcfg
tool.
Setting the module type to sufficient
means that if Yubikey authentication succeeds, no further steps will be processed and the user will get logged in. This is the key point which enables passwordless logins. However, in the event of authentication failure, remaining authentication steps will still be applied, i.e. the user can still log in with their password if the Yubikey is not plugged in.
If the module type is set to required
instead of sufficient
it will enable Two-Factor Authentication (2FA) which will require the user to plug in their Yubikey and enter their password to login.
Note: For passwordless logins the user will need to press the
Enter
with their Yubikey plugged in to unlock their screen.
At this stage you should be able unlock your screen with they Yubikey.
Note: You may need to replug your Yubikey for the changes to take effect.
Automatically locking the screen when Yubikey is unplugged
Up till locking the screen still requires manually invoking the xlock
command. It would be nice if we can somehow automatically lock the screen whenever our Yubikey is unplugged. We can achieve this with Udev.
Udev is the device manager used in Linux which can be used for a myriad of tasks. It tracks the state changes for all external devices, for example, it can be used to identify when a USB device is plugged or unplugged. Each device outputs a series of attributes which can be used to uniquely identify it.
We shall use these attributes to create a Udev rule which triggers an xlock.service
Systemd service when the Yubikey is unplugged.
Note: We can also achieve this with a Shell script instead of Systemd, but Udev discourages executing long-running programs using scripts as it terminates them after a certain time period.
Creating the Systemd service
Systemd is the Linux service manager which can be used to launch user processes. We create a file named xlock.service
in the /etc/systemd/system/
directory:
$ cat /etc/systemd/system/xlock.service
[Unit]
Description=xlock
[Service]
User=adeel
Type=simple
Environment=DISPLAY=:0
ExecStart=/usr/bin/xlock
[Install]
WantedBy=multi-user.target
- The
Type=simple
implies that this service does not exit after execution. - The
Environment
tag specifies which display should be locked (0
is the default display). - The
ExecStart
tag takes a path of the binary or script it will execute.
Note: Consult the official docs to explore Systemd in detail.
Creating the Udev rule
We first need to identify a set of unique attributes for our device (Yubikey). The udevadm
tool allows monitoring Udev output whenever a device state changes. We shall invoke the following command and then remove our Yubikey:
$ udevadm monitor --environment --udev
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
UDEV [461872.738673] remove /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.1/1-2.1:1.0/0003:1050:0407.0157/input/input294/event18 (input)
ACTION=remove
ID_VENDOR=Yubico
SUBSYSTEM=input
DEVNAME=/dev/input/event18
ID_INPUT_KEY=1
...
We only show a truncated output above, but once you have identified the attributes you would like to use, create a file named yubikey-actions.rules
in the /etc/udev/rules.d/
directory:
$ cat /etc/udev/rules.d/yubikey-actions.rules
ACTION=="remove", ENV{ID_MODEL_ID}=="0407", ENV{ID_VENDOR_ID}=="1050", RUN+="/usr/bin/systemctl start xlock.service"
It might be worthwhile to reload the configuration for both Systemd and Udev:
$ systemctl daemon-reload
$ udevadm control --reload
If everything worked out fine your screen should now get locked whenever you remove your Yubikey.