Note: This article infers that you have already configured a U2F device (like a Yubikey), and Google Authenticator. Also, when running pamu2fcfg
, run it with the -P
option.
Update: It turns out that repository package of pam-u2f
version 1.0.8
didn’t support the userpresence=0
option necessary to disable the request for pressing the tactile trigger twice; this option is only supported by FIDO2-capable devices, which was clarified in this GitHub issue by the very knowledgeable (and patient) Alessio Di Mauro.
I’ve been interested in creating a similar authentication flow for my computers to the one we usually encounter on several popular websites (depicted in this Stack Exchange answer). This mainly consists of the following steps:
- Enter username & password to authenticate
- If available, use a U2F device as the second factor authentication (like Yubico’s Yubikey)
- Otherwise, ask for a verification code (from, for example, Google Authenticator)
At first, I wanted to implement my own PAM module, but I’m still not confident enough to not shoot myself in the foot; then I tried my hand at cobbling something together with the pam_exec.so
module, but realized that it wasn’t able to pass user input to a script, and in turn making it impossible to make use of the success=n
action.
After reading a lot of documentation, I was able to put together something useful, without the need for extra dependencies (other than libpam-u2f
, and libpam-google-authenticator
).
# What the following lines accomplish:
# Prompt for a U2F device, and to then press ENTER.
# In case the U2F device is known, prompt the user to press the tactile trigger.
# In case the U2F device is not know or present, prompt for a verification code from Google Authenticator.
# Allow users that are not configured to use U2F or Google Authenticator to log in.
auth [success=1 new_authtok_reqd=ok ignore=ignore default=ignore] pam_u2f.so interactive userpresence=0 nouserok authfile=/etc/Yubico/u2f_keys
auth [success=1 new_authtok_reqd=ok ignore=ignore default=bad] pam_google_authenticator.so nullok
auth required pam_u2f.so cue userpresence=1 nouserok authfile=/etc/Yubico/u2f_keys
Sources:
- https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html
- https://github.com/google/google-authenticator-libpam/
- https://github.com/Yubico/pam-u2f
- https://modusmundi.com/2020/02/12/adding-u2f-to-your-login-in-linux/
- https://www.raczylo.com/blog/openvpn-with-yubikey-and-google-authenticator/
- https://support.yubico.com/support/solutions/articles/15000011356-ubuntu-linux-login-guide-u2f
- https://wpollock.com/AUnix2/PAM-Help.htm
Note: As it was mentioned in the Update above, the desired behaviour would only be achieved with a modern FIDO2-capable device (as was discussed in this GitHub issue). However, for backwards compatibility with devices that don’t support U2F 1.2, I’ve included a version of the code that would require a double touch of the tactile trigger., but still work as intended.
# What the following lines accomplish:
# Prompt for a U2F device, and to then press ENTER.
# In case the U2F device is known, prompt the user to press the tactile trigger (twice).
# In case the U2F device is not know or present, prompt for a verification code from Google Authenticator.
# Allow users that are not configured to use U2F or Google Authenticator to log in.
auth [success=1 new_authtok_reqd=ok ignore=ignore default=ignore] pam_u2f.so interactive cue nouserok authfile=/etc/Yubico/u2f_keys
auth [success=1 new_authtok_reqd=ok ignore=ignore default=bad] pam_google_authenticator.so nullok
auth required pam_u2f.so cue nouserok authfile=/etc/Yubico/u2f_keys