PAM is amazingly flexible and playing around with it can render your system inoperable. So if you love the thrill of editing a file without testing you are going to love adding a yubikey as a login option to your system.

All jokes aside, having a root login terminal, and a backup of the files you are editing is enough to not lock you out of a system. On to the fun part! We are going to modify 2 files under /etc/pam.d/. u2f and system-auth. The goal here is to completely skip typing our amazingly long and secure password and tap our yubikey whenever we want to login or perform administrative access using sudo or other access elevation programs. If you accidentally break PAM and realise you cannot login after rebooting. You will need to start up in “single-user-mode”, which can be achieved by adding init=/bin/bash to your boot manager, such as grub. Or you can just use that trusty live iso you have laying around so you can mount your system and edit PAM back to its original system.

Required Reading

  • https://wiki.gentoo.org/wiki/YubiKey
  • https://support.yubico.com/hc/en-us/articles/360016649099-Ubuntu-Linux-Login-Guide-U2F

Optional Reading

Learn more about what we are actually doing by reading up on how PAM works

  • https://wiki.gentoo.org/wiki/PAM

There is a wealth of knowledge in the above links and they cover how to correctly perform a setup and mapping of your yubikey so that you can login with/without a yubikey. Once you have added your yubikeys to your ~/.config/Yubico/u2f_keys you can see what a successful PAM setup looks like for touch login and touch sudo.

Touch Login & Touch Sudo

We create a single PAM config file with our settings that we can use include on any subsequent file changes. Changing sufficient to required here would make everything require 2FA, instead of everything accepting just your yubikey (or just your password).

  • /etc/pam.d/u2f
    auth            sufficient      pam_u2f.so      cue
    

We then add the first 3 auth lines to our system-auth which allow us to login with u2f, and if it is successful, skip passed the next auth line, (which is the failure). We then modify pam_env.so to also be sufficient instead of required as before.

  • /etc/pam.d/system-auth
    auth            include         u2f
    auth            [success=1 default=ignore]      pam_unix.so nullok  try_first_pass
    auth            [default=die]   pam_faillock.so authfail
    auth            sufficient      pam_env.so
    auth            requisite       pam_faillock.so preauth
    ... snip ...
    

Note: I’ve only included the auth lines in all the files, as they were the only changes needed. Do note delete any of the other account, password, session lines etc.

Note 2: The last two lines may not appear in your config, if so leave them out!

Testing!

At this point if you never took a backup, I assume you left a root terminal open so if you broke your authentication by mistyping the above, or not realising pam_u2f.so is not the library that came with your distribution you can quickly revert your changes…

The options to test to confirm everything works as you expect:

  • sudo with yubikey in
    • Result: Touch only ✓
  • sudo without yubikey
    • Result: Password only ✓
  • login with yubikey in
    • Result: Touch only ✓
  • login without yubikey
    • Result: Password only ✓

These 4 options can be tested by using the login command, which opens up a new login terminal so you will be able to test the new login functionality, without having to actually logout of your working system.

Please touch your device

Congratulations! We now no longer have to type our password when logging in, or when we type sudo. You may be wondering why if we never modified the sudo file under /etc/pam.d how does it still allows us to use our key as a sufficient authentication mechanism. If you take a peek into the sudo file, the first line (should be) auth substack system-auth. Sudo utilises system-auth for authentication.

If you don’t like that, and for example, only wanted to login with the yubikey you would revert your system-auth file, and would modify your login-managers-password file accordingly. For example, you would modify gdm-password for gdm.

Thoughts…?

You read this far? I like you!

One of the interesting edge cases (for me) and the reason I wrote this post was I never changed the pam_env.so line to sufficient and I could not find any references about it either. If I left it as required it resulted in password authentication failing, but yubikey auth being successful. These are the edge cases I like finding out about, and investigating.

I think PAM needs a better fail safe feature so you don’t have to worry about locking yourself out. It would probably be very difficult to implement as PAM has so many use cases. Maybe something as simple as a critical path flowchart in ascii (or png) that you can view would be better than nothing. Visualising each step of success and failure may highlight an insecurity. (IE: what is my pam_env file doing here. I’m sure it is from a previous change I made but for the life of me I’m not sure why :D)