Pop OS/Ubuntu: Detecting USB Security Key Events

Security keys such as the Yubikey from Yubico have become much more popular in recent times, showing an increased focus on security best practices. Many people are already aware of Multi-Factor Authentication or MFA, since many secure online services (e.g. banks, government portals) have mandated the use of a physical device or one-time access codes before using their services. To learn more about MFA, please check out the Wikipedia article on MFA.

Since you’re here, you know what MFA is so let’s look at what I needed to achieve. Simply:

Upon USB security key insertion or removal, detect that event and “do something” in response.

– My requirements 🙂

My environment:

  • Pop OS 21.04 Linux (based on Ubuntu)
  • Yubikey USB security key

What I’m not going to cover:

  • How to configure your Yubikey for use in Linux. To learn more, please see the official Yubico documentation
  • Which Linux distributions use or don’t use udev – that’s on you

Get Info About Security Key

For all this to work, we’ll rely on udev. Using the built-in tools that are provided with various Linux distributions, we first need to get some info about your security key. Your output will vary greatly depending on events happening in your system and also on the model of security key you are using.

  • Disconnect/remove your security key from your system
  • Open a terminal and start monitoring udev events:
udevadm monitor --property

Successfully starting the monitor will show this:

~ ❯
~ ❯ udevadm monitor --property
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

Note: In the output below, I’ve removed some info and replaced it with [removed].

  • Insert your security key and note the extensive output shown in your terminal window. The specific section looks like this on my system:
UDEV  [52954.592536] add      /devices/pci0000:40/0000:40:01.1/0000:41:00.0/0000:42:08.0/0000:48:00.3/usb9/9-4/9-4:1.0/0003:1050:0407.001C/input/input40/event6 (input)
ACTION=add
DEVPATH=/devices/pci0000:40/0000:40:01.1/0000:41:00.0/0000:42:08.0/0000:48:00.3/usb9/9-4/9-4:1.0/0003:1050:0407.001C/input/input40/event6
SUBSYSTEM=input
DEVNAME=/dev/input/event6
SEQNUM=28039
USEC_INITIALIZED=52954592318
ID_INPUT=1
ID_INPUT_KEY=1
ID_INPUT_KEYBOARD=1
ID_VENDOR=Yubico
ID_VENDOR_ENC=Yubico
ID_VENDOR_ID=1050
ID_MODEL=[COPY_THIS_VALUE]
ID_MODEL_ENC=[removed]
ID_MODEL_ID=[removed]
ID_REVISION=[removed]
ID_SERIAL=[removed]
ID_TYPE=hid
ID_BUS=usb
ID_USB_INTERFACES=:030101:030000:0b0000:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=usbhid
.INPUT_CLASS=kbd
ID_PATH=pci-0000:48:00.3-usb-0:4:1.0
ID_PATH_TAG=pci-0000_48_00_3-usb-0_4_1_0
XKBLAYOUT=au
BACKSPACE=guess
XKBMODEL=pc105
XKBVARIANT=
XKBOPTIONS=
ID_SECURITY_TOKEN=1
ID_FOR_SEAT=input-pci-0000_48_00_3-usb-0_4_1_0
.LOCAL_ifNum=00
LIBINPUT_DEVICE_GROUP=3/1050/407:usb-0000:48:00.3-4
MAJOR=13
MINOR=70
DEVLINKS=[removed]
TAGS=:uaccess:power-switch:seat:
CURRENT_TAGS=:uaccess:power-switch:seat:
  • Three things are of particular interest here:
    • ACTION is add
    • SUBSYSTEM is input
    • ID_MODEL is YubiKey_[some_stuff_here] – note down the value of this property now, as you’ll need it shortly
  • Remove your security key and again note the extensive output shown in the terminal. The relevant block looks similar to before but with one main difference:
    • ACTION is remove
  • Hit Ctrl-C to stop the udev monitoring

Now that we have the necessary info about our security key, we can proceed.

The “Do Something” Part

The “do something” part of this article will be different for everyone, meaning the scripts below are examples only. Here are the components of this setup:

  • Script called yubikey, located in my home directory:
#!/bin/bash

if [ "$1" == "removed" ]
then
    echo "Oi, Yubikey has been removed!" > /home/me/yubikey_status.txt
else
    echo "K, Yubikey found.  Secure all the things!" > /home/me/yubikey_status.txt
fi
  • Text file named yubikey_status.txt in my home directory:
unknown
  • The watch command can be used to monitor file contents:
watch cat ~/yubikey_status.txt

Reacting to a security key removal event will likely be accompanied with an action such as locking the screen, sending an email or displaying a message. For now, this is what we’ll see:

Every 2.0s: cat /home/me/yubikey_status.txt

unknown

Detecting Security Key Insertion/Removal

udev will be used to handle the USB insertion/removal events, using custom udev rules stored in /etc/udev/rules.d.

Privilege escalation via sudo (or similar) will be required to create and edit these files.

To learn more about how these files are named, please see the official udev documentation.

  • Create a file named /etc/udev/rules.d/90-yubikey.rules, containing the following content:
ACTION=="add", SUBSYSTEM=="input", ENV{ID_MODEL}=="[ID_MODEL_COPIED_EARLIER_GOES_HERE]", RUN+="/home/me/yubikey inserted"
ACTION=="remove", SUBSYSTEM=="input", ENV{ID_MODEL}=="[ID_MODEL_COPIED_EARLIER_GOES_HERE]", RUN+="/home/me/yubikey removed"

These udev rules complete the following actions:

  • Watches for both add and remove events
  • Matching events must occur in the INPUT subsystem
  • The matching events must occur for devices matching the specified ID_MODEL
  • When a matching event occurs, the ~/yubikey script executes
    • inserted command-line parameter if the device was added
    • removed command-line parameter if the device was removed
  • The ~/yubikey script will write content to the ~/yubikey_status.txt file depending on the value of the $1 parameter i.e. the first parameter on the command line

Reloading udev Configuration

We can dynamically reload the udev rules by running the following command:

sudo udevadm control --reload

Testing

  • Run the watch command above if it’s not already running
  • Insert your security key
  • If everything has been configured correctly and your udev rules have been reloaded, you’ll see the watch command output change as follows:
Every 2.0s: cat /home/me/yubikey_status.txt

K, Yubikey found.  Secure all the things!
  • Conversely, removing the security key will run the script again, causing the output to change as follows, as the contents of the ~/yubikey_status.txt file changes:
Every 2.0s: cat /home/me/yubikey_status.txt

Oi, Yubikey has been removed!

Wrapping Up

That’s all there is to it. Hopefully this was useful for someone.