A FIDO2 security key is good for more than web services such as GitHub, Google or other passkey-compatible offerings. Through the PAM module pam-u2f you can tie a FIDO2 key straight into the authentication of your Linux system.
The security key then covers sudo, su or the graphical login. Instead of typing a password, you plug in the key and confirm the request with a touch. The key thereby takes on a central role in signing in.
This guide applies to the Nitrokey FIDO2, to YubiKeys and to other compatible U2F and FIDO2 authenticators. Alongside YubiKeys, pam-u2f expressly supports other devices that speak the U2F or FIDO2 standard.
Note: We tested the configuration described here with a Nitrokey FIDO2 under TUXEDO OS 24.04 only. With other FIDO2 keys, with Ubuntu or Debian derivatives and with other display managers, individual steps or configuration files may differ.
In this guide you set up the FIDO2 key for three cases:
- authentication with sudo
- switching users with su
- graphical login through SDDM
The examples use the Linux user tux. At the end of the article you will also find a digression on why a FIDO2 key cannot readily unlock LUKS at boot under TUXEDO OS at present.
PAM and pam-u2f under Linux
PAM stands for „Pluggable Authentication Modules“. It is a Linux infrastructure through which programs hand authentication over to separate modules. Applications therefore do not have to build the individual authentication methods themselves.
Rather than checking on its own whether a password, a smartcard or a FIDO2 key comes into play, a program passes authentication to PAM. Different applications can thus share the same authentication methods without each having to provide them separately.
For authentication with a FIDO2 key, the module pam_u2f does the work. It comes from Yubico’s pam-u2f project. Despite the name, the module supports modern FIDO2 authenticators alongside the older U2F standard.
Installing the required packages
Under TUXEDO OS you install pam-u2f straight from the package sources. Open a terminal and install the required packages:
sudo apt update
sudo apt install libpam-u2f pamu2fcfg
The package libpam-u2f contains the PAM module itself. pamu2fcfg registers a FIDO2 key and generates the configuration needed for it. The official pam-u2f documentation names both packages for Ubuntu as well.
You can install the FIDO2 tools on top of that. Among other things, they help you spot connected security keys and check their properties:
sudo apt install fido2-tools
fido2-token -L then shows whether the system recognises the connected key:
fido2-token -L
(out)/dev/hidraw1: vendor=0x20a0, product=0x42b1 (Nitrokey Nitrokey FIDO2 2.4.0)
As an alternative, lsusb tells you whether the security key turns up on the USB bus:
lsusb
(out)[...]
(out)Bus 003 Device 007: ID 20a0:42b1 Clay Logic Nitrokey FIDO2 2.4.0
Registering the FIDO2 key
Next you register the FIDO2 key for your Linux user. Plug in the Nitrokey and run the following command as the user tux:
pamu2fcfg -u $USER
The program then asks you to touch the security key. After a successful registration, pamu2fcfg prints a configuration line. Among other things, it holds the cryptographic credential of the FIDO2 key:
tux:3...d/5FA==,es256,+presence
The real line is a good deal longer. The entry +presence means that authentication checks the physical presence of the user. You therefore have to operate the security key yourself, as a rule by touching it.
pamu2fcfg applies this check by default. -P, or --no-user-presence, switches it off. For a physical security key you should normally leave the option alone, since it drops an additional safeguard.
Creating the credential file
pam-u2f needs a mapping between the Linux user and the registered FIDO2 credential. By default it can live in the user’s home directory under ~/.config/Yubico/u2f_keys.
For several PAM services, however, a central file is handier. This guide uses /etc/u2f_mappings for that purpose. sudo, su and the display manager can then share the file.
First create the file with suitable ownership and permissions:
sudo install -o root -g root -m 600 /dev/null /etc/u2f_mappings
Then write the registration you created earlier straight into the file:
pamu2fcfg -u $USER | { cat; printf '\n'; } | sudo tee -a /etc/u2f_mappings
The Nitrokey has to be connected and touched when prompted. The file then holds a line along these lines:
tux:3...d/5FA==,es256,+presence
The real credential line should neither be published nor passed on to others. /etc/u2f_mappings therefore carries permissions 600 and is readable by root alone.
pam-u2f also supports several FIDO2 authenticators. You can therefore register a second security key as a spare later on. The additional credentials go into the same mapping file.
Configuring FIDO2 for sudo
Now you switch on the Nitrokey for sudo. The matching PAM configuration sits in /etc/pam.d/sudo.
Warning: Before you change anything in PAM, keep a second root shell open, or at least one other working login. A faulty PAM configuration can cut off access to user accounts or root privileges.
Open the file, for instance with:
sudoedit /etc/pam.d/sudo
Look for the existing line:
@include common-auth
Add the following line above it:
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
The relevant section then reads:
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
@include common-auth
sudo can now try the FIDO2 key first. One successful authentication is enough. If the key is missing or FIDO2 authentication fails, the normal authentication through common-auth takes over.
That gives you two routes: Nitrokey connected » touch the Nitrokey » authentication succeeds, or Nitrokey unavailable » type the password » authentication succeeds. You can therefore run a command such as the following without typing your user password:
sudo apt update
The prerequisite is a connected Nitrokey and a touch to confirm the request.
Testing sudo
After the change, test sudo on its own first. sudo -k clears any cached authentication:
sudo -k
sudo -v
sudo should now recognise the FIDO2 key and ask for a touch. Confirm the request by touching the Nitrokey.
Check the password fallback afterwards. Unplug the Nitrokey, run sudo -k again and then start a sudo command. The usual password prompt should appear.
Both routes should work before you move on to the next PAM configurations.
Configuring FIDO2 for su
su goes through PAM as well and can therefore authenticate through pam_u2f. The matching configuration sits in /etc/pam.d/su. Add the following line to the auth section there too:
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
A typical configuration can look like this:
# This allows root to su without passwords (normal operation)
auth sufficient pam_rootok.so
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
Leave the existing pam_rootok.so line in place. It lets root switch users through su without further authentication.
Note as well that the credential of the user tux does not carry over to root. If the Nitrokey is to serve for a switch to root, then root needs a credential of its own.
Configuring FIDO2 for root
The following command switches you to the user root. For the login you type the dedicated root password, which you set under TUXEDO OS with sudo passwd root.
su -
If the FIDO2 key is to handle authentication here, first register a credential for root:
pamu2fcfg -u root | { cat; printf '\n'; } | tee -a /etc/u2f_mappings
The printed line lands in /etc/u2f_mappings as an additional credential. The file then holds:
cat /etc/u2f_mappings
(out)tux:rL...0Q==,es256,+presence
(out)root:43...Dg==,es256,+presence
The FIDO2 key can now authenticate you as root as well. In day-to-day work, though, you should weigh whether you need su at all. On Ubuntu and systems derived from it, sudo is the customary route for administrative tasks.
Configuring FIDO2 for the graphical login
Next you can put the FIDO2 key to work for the graphical login. TUXEDO OS with KDE Plasma uses SDDM (Simple Desktop Display Manager) for that by default. SDDM draws on PAM for authentication as well. The matching settings sit in /etc/pam.d/sddm.
Here too, add the following line to the auth section above @include common-auth:
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
Do not replace the whole existing PAM configuration while doing so. The entries already there stay. Add the FIDO2 line at a suitable spot in the authentication section and nothing else. After the edit, the head of the file should read roughly like this:
#%PAM-1.0
# Block login if they are globally disabled
auth requisite pam_nologin.so
auth required pam_succeed_if.so user != root quiet_success
# auth sufficient pam_succeed_if.so user ingroup nopasswdlogin
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
@include common-auth
# gnome_keyring breaks QProcess
-auth optional pam_gnome_keyring.so
-auth optional pam_kwallet5.so
[...]
The resulting sequence runs like this: SDDM » pick your user » plug in the Nitrokey » touch the Nitrokey » press Enter » KDE Plasma starts. Since common-auth remains as a fallback, you can still sign in with your normal user password whenever the Nitrokey is out of reach.
Why a central file pays off
For sudo, a credential file in the user’s home directory can do the job. For the graphical login it is less practical, because the display manager handles authentication before the user session starts.
A central file such as /etc/u2f_mappings therefore suits this case. It stands available to the various PAM services independently of the home directory and can be shared by sudo, su and SDDM.
The central file also eases the handling of several security keys. If you want a second FIDO2 authenticator as a spare, you can store its credential in the same file.
Nitrokey, YubiKey or password?
The configuration described here deliberately uses the PAM control flag sufficient:
auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
One successful FIDO2 authentication is therefore enough. If it fails, or if the key is out of reach, the password authentication that follows through common-auth can take over.
This is not classic two-factor authentication. Instead, two alternative routes stand side by side: Nitrokey plus touch, or the familiar password prompt.
A true two-factor setup would ask for the password first and the FIDO2 key afterwards. That is possible as well, but calls for a different PAM configuration.
PIN and user verification
Besides user presence, FIDO2 can call for a PIN, also known as „user verification (UV)“. That adds another layer to the authentication.
The following command registers a credential that calls for PIN verification:
pamu2fcfg -u tux -N
pamu2fcfg supports the following options, among others:
pamu2fcfg --help
(out)[...]
(out) -P, --no-user-presence Allow the credential to be used without ensuring the
(out) user's presence (default=off)
(out) -N, --pin-verification Require PIN verification during authentication
(out) (default=off)
(out) -V, --user-verification Require user verification during authentication
(out)[...]
For the configuration described here, a registration with user presence is normally enough. The printed credential then carries +presence.
Which variant makes sense depends on the security level you want and on the FIDO2 authenticator in use. Support for individual features can differ from one security key to the next.
Notes and tips
What happens if you lose the Nitrokey?
If you use a security key for signing in to Linux, give some thought to failure while you set it up. A lost, damaged or momentarily missing key should not lock you out of your system for good.
The most straightforward answer is to keep the password as a fallback. The configuration described here with auth sufficient does exactly that.
Safer still is a second FIDO2 authenticator held in reserve. pam-u2f supports several authenticators, so you can carry one key day to day and keep a second one in a safe place.
Keep a second root session open
While setting things up, keep a working root shell open alongside:
sudo -i
Close that shell only once you have tested the changes successfully. This goes for changes to /etc/pam.d/sudo, /etc/pam.d/su and /etc/pam.d/sddm in particular. All configuration changes described here take effect without a reboot.
Should a PAM configuration contain a mistake, you can correct the file through the root shell you left open. That keeps a faulty configuration from locking you out of your own system.
What to do when the login stops working
Should a faulty PAM configuration block the graphical login, you can switch to a virtual console, depending on your system. Under TUXEDO OS, Ctrl+Alt+F3 opens one.
Sign in there with a user account that still works and correct the PAM configuration in question. If signing in at a virtual console fails as well, a recovery system or a live system may be needed.
With changes to /etc/pam.d/sddm above all, you should therefore close your existing graphical session only after testing the FIDO2 login successfully.
Do not carry the configuration over blindly
PAM configurations differ by distribution, by version and by display manager. The package versions on offer can differ as well. The paths and settings shown here therefore refer to the test environment described above.
We tested the configuration with TUXEDO OS, KDE Plasma, SDDM, pam-u2f and a Nitrokey FIDO2. The underlying method carries over to Debian, Ubuntu and other Linux distributions that use PAM.
The procedure also works with a YubiKey and with other U2F- and FIDO2-compatible security keys. Differences can arise depending on the model, on its FIDO support, on the distribution and on the PAM version in use.
Beyond the login: FIDO2 for unlocking LUKS at boot
The configuration described so far takes hold once the system is already running. The obvious follow-up question is whether a FIDO2 key can unlock a system partition encrypted with LUKS (Linux Unified Key Setup) as well. The groundwork for that exists: with systemd-cryptenroll you enrol a FIDO2 authenticator into a LUKS2 container, and the data needed for it then sits in the LUKS2 header.
The catch sits one layer down, in the initramfs. Debian and the distributions built on it generate it with initramfs-tools, and its cryptsetup integration does not know the option fido2-device in /etc/crypttab. Generating the initramfs prints ignoring unknown option 'fido2-device' instead. This is not behaviour peculiar to TUXEDO OS but an open gap in Debian itself: it has been on file as a bug report against the package cryptsetup-initramfs since November 2022 and remains open to this day.
Note: A workaround doing the rounds is a switch from initramfs-tools to dracut. Dracut falls back on systemd-cryptsetup for unlocking and therefore copes with fido2-device. The route works, but it swaps out the initrd generator of the entire system. For an intervention that deep into the boot chain we see no reasonable payoff on a work machine, and we therefore do not recommend it.
If you want to pursue LUKS unlocking regardless, fido2luks offers a far less invasive approach. The project hooks into initramfs-tools through a keyscript rather than replacing the initrd generator. It reads the FIDO2 data that systemd-cryptenroll stored in the LUKS2 header and can thus put the security key to work during boot. The keyscript goes into /etc/crypttab, after which you generate the initramfs anew.
Warning: fido2luks (more on GitHub) is not part of the supported TUXEDO OS configuration. In Debian the package sits in testing and unstable only, not in the stable package sources. Anyone using it leaves the path we have tested and cannot expect support for it.
Changes to LUKS, to /etc/crypttab and to the initramfs can leave the system unable to boot. Before you generate the initramfs anew, therefore keep a working second LUKS key and a live system for recovery within reach.
For this guide, then, it stays with pam-u2f for sudo, su and the graphical login. We tested those three cases under TUXEDO OS, they leave the boot chain untouched, and the password remains as a fallback.