header image

Are you looking for a cheap and trustworthy two-factor authentication solution for your Linux computer or computers? You should take a look at USB PAM authentication module which let you to establish either a simple or complicated authentication rules and actions for each Linux user depending on your needs and environment. The module stacks on top of your existing solutions such as basic password or LDAP authentication and adds extra layer of security.

Table of Contents


Foreword

USB-based authentication offers a cheap and extremely modular solution which does not require any extra devices such as fingerprint scanners, card readers or anything a like for unique user authentication. Additionally, you do not encounter any software or platform compatibility issues such as lack of vendor support. Just pick a USB storage device of your choice, configure system and that's all. Obviously, you can configure as many USB devices as you want or need (e.g. for multiple users) with different action policies.

Requirements

You need to install and configure PAM USB module on your Linux system.

How it works

Adding new devices and users

At first you need to add an USB storage device which you link to a valid Linux user name. Attach your USB storage device and run sudo pamusb-conf --add-device=<name-of-your-choice> afterwards. This adds the device configuration into USB PAM configuration file /etc/security/pam_usb.conf. For adding users, you may use command sudo pamusb-conf --add-user=<valid-linux-user-name> or simply manually edit the XML styled configuration file /etc/security/pam_usb.conf. See configuration documentation for an example.

The configuration file pam_usb.conf is used by PAM USB module library file pam_usb.so and PAM USB Agent (pamusb-agent) daemon service (explained later).

Good PAM policy

Depending on your security aspects, you may want to use one of the following PAM policies into your /etc/pam.d/system-auth file (file name may vary depending on your Linux distribution):

Testing phase: USB storage is sufficient for full authentication, no password asked

This is recommended setting in testing phase since you don't want to lock yourself out from your system.

1auth      sufficient pam_usb.so
2auth      required  pam_unix.so     try_first_pass nullok nodelay
3auth      optional  pam_permit.so
4auth      required  pam_env.so

Production environment phase: Require USB storage to be attached

This is recommended setting in production phase where everything has been confirmed to work as expected.

1auth      required  pam_usb.so
2auth      required  pam_unix.so     try_first_pass nullok nodelay
3auth      optional  pam_permit.so
4auth      required  pam_env.so

su command

For su and su --login commands, edit /etc/pam.d/su and /etc/pam.d/su-l. Simply add auth required pam_usb.so as the first line in the files.

Desktop users

The PAM USB Agent does not work if you do not properly configure desktop related PAM configuration files. For instance, LightDM and KDE/Plasma 5 use additional configuration installed into /etc/pam.d folder. Symptoms are that lock screen etc. are not triggered when you unplug your USB storage device. For lock screen actions, you need additional configuration in /etc/security/pam_usb.conf and the PAM USB Agent Systemd daemon service.

Creating action rules

By adding pam_usb.so into PAM configuration, authentication works properly on command line. If you need fine-grained USB action policy, use the PAM USB Agent Systemd service. Without it, there is no way to control USB related actions, and if you're on a desktop environment, lock screen functionality does not work. In a nutshell, you need to

    1. configure desired lock and unlock agent events in /etc/security/pam_usb.conf for user/device
    1. enable and start the PAM USB Agent Systemd service daemon pamusb-agent.service

For lock screen actions, see configuration documentation - Example for an example.

For KDE/Plasma 5, you may use the following agent event pattern:

1<agent event="lock">
2        <env>DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus</env>
3        <cmd>dbus-send --session --dest=org.freedesktop.ScreenSaver --type=method_call /org/freedesktop/ScreenSaver org.freedesktop.ScreenSaver.SetActive boolean:true</cmd>
4        <!-- <cmd>qdbus org.freedesktop.ScreenSaver /ScreenSaver Lock</cmd> -->
5</agent>

This is from my personal configuration. I don't have anything for unlock event.

post image
The PAM USB module configured for user fincer and USB storage device known as microDuo. User attempts to modify DNS server (bind9) main configuration file and at first, the valid USB device is required and properly detected after which user password is also required for sudo action (2FA).

Implementation changes

In the original PAM USB implementation by Andrea Luzzardi, the PAM USB Agent service is separately run for each user. In my implementation, the agent service runs as root and controls all USB actions for all configured users. This change is for easier set-up, maintenance and configuration.

Several other changes have also been made:

  • lock and unlock actions can take multiple chained commands with multiple environment variables. Commands have no environment variables by default for security reasons.

  • minor linguistic changes (more proper use of language)

One-time pads

The PAM USB module uses one-time pads (OTP) for each device by default. One-time pads? I recommend reading Wikipedia article One-time pad if you are not familiar with the concept.

Practically, these work so that a decice-specific .pad file is generated in system_pad_directory. New pad file is generated after desired expiration time (pad_expiration). If you do not want to use OTP feature, disable it by adding the following XML configuration into /etc/security/pam_usb.conf:

1<option name="one_time_pad">false</option>

For instance, if I wanted to disable one-time pad for one of my Kingston DataTraveler 2.0 USB storage device, I should use:

1<device id="kingston">
2    <vendor>Kingston</vendor>
3    <model>DataTraveler 2.0</model>
4    <serial>XXXXXXXXXXXXXXXXXXXXXXXX</serial>
5    <volume_uuid>aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</volume_uuid>
6    <option name="one_time_pad">false</option>
7    <!-- <option name="pad_expiration">0</option> -->
8</device>

Combine with USBGuard

You can even more enchance the USB device security by using USB Guard service which controls allowed, rejected and blocked USB devices. It basically protects your system against rogue USB devices: For instance, you can reject all other USB devices except your USB authentication storage device and other critical USB devices.

See also the USBGuard official website.

Conclusions

The PAM USB module is good security addition to critical Linux environments where there's a risk for rogue actions or users. I use it both on my server environment and personal laptop, and it works pretty well on both. You should always use sufficient PAM policy with pam_usb.so before making it a strict requirement since misconfigurations may happen.