With the rise of WebAuthn, I've had to figure out how expose my various FIDO security keys (YubiKey, Nitrokey, OnlyKey, SoloKeys, etc) to the LXD containers I use for web browsers.
The core of the solution is to expose the HIDRAW device that the security key is using to the LXD container — and to configure the device in the container to be owned by the user account who will use it. If you only have one such key plugged in, it's most likely using the /dev/hidraw0 device; and usually it's user 1000 who needs to use it. An LXD profile entry like the following allows such access:
config: {} description: exposes FIDO devices devices: hidraw0: required: false source: /dev/hidraw0 type: unix-char uid: "1000" name: fido used_by: []
A profile like this can be created, configured, and applied to a container with the following commands:
$ lxc profile create fido Profile fido created $ lxc profile device add fido hidraw0 unix-char required=false source=/dev/hidraw0 uid=1000 $ lxc profile add mycontainer fido Profile fido added to mycontainer
However, the exact HIDRAW device number that a particular security key uses is not stable, and may vary as you plug and unplug various keys (or other USB or Bluetooth devices). How do you tell which HIDRAW device is being used by a particular physical device? The simplest way is to print out the content of the uevent pseudo file in the sysfs filesystem corresponding to each HIDRAW device until you find the one you want. For example, this is what the entry for one of my SoloKeys looks like, at hidraw11:
$ cat /sys/class/hidraw/hidraw11/device/uevent DRIVER=hid-generic HID_ID=0003:00001209:0000BEEE HID_NAME=SoloKeys Solo 2 Security Key HID_PHYS=usb-0000:00:14.0-4/input1 HID_UNIQ=1234567890ABCDEF1234567890ABCDEF MODALIAS=hid:b0003g0001v00001209p0000BEEE
You can also get similar information — without the specific device name, but with the general type of device, like FIDO_TOKEN — from the udevadm command:
$ udevadm info /dev/hidraw11 P: /devices/pci0000:00/0000:00:24.0/usb1/2-4/2-4:1.4/0003:1209:BEEE.0022/hidraw/hidraw11 N: hidraw11 L: 0 E: DEVPATH=/devices/pci0000:00/0000:00:24.0/usb1/2-4/2-4:1.4/0003:1209:BEEE.0022/hidraw/hidraw11 E: DEVNAME=/dev/hidraw11 E: MAJOR=232 E: MINOR=12 E: SUBSYSTEM=hidraw E: USEC_INITIALIZED=123456789010 E: ID_FIDO_TOKEN=1 E: ID_SECURITY_TOKEN=1 E: ID_PATH=pci-0000:00:24.0-usb-0:4:1.4 E: ID_PATH_TAG=pci-0000_00_24_0-usb-0_4_1_4 E: ID_FOR_SEAT=hidraw-pci-0000_00_24_0-usb-0_4_1_4 E: TAGS=:uaccess:seat:snap_firefox_geckodriver:security-device:snap_firefox_firefox: E: CURRENT_TAGS=:uaccess:seat:snap_firefox_geckodriver:security-device:snap_firefox_firefox:
Using the udevadm info and lxc profile device list and commands, you can write a simple script that checks each /dev/hidraw* device on your host system against the HIDRAW devices registered for a particular LXD profile, and add or remove HIDRAW devices dynamically to that profile to match the current FIDO devices you have plugged in. Here's such a script:
#!/bin/sh -eu profile=${1:-fido} existing=$(lxc profile device list $profile) for dev_path in /dev/hidraw*; do dev_name=$(basename $dev_path) if udevadm info $dev_path | grep FIDO >/dev/null; then if ! echo "$existing" | egrep '^'$dev_name'$' >/dev/null; then lxc profile device add $profile $dev_name \ unix-char required=false source=$dev_path uid=1000 fi else if echo "$existing" | egrep '^'$dev_name'$' >/dev/null; then lxc profile device remove $profile $dev_name fi fi done echo done
You can run the script manually every time you plug in a new security key, to make sure the security key is registered at the right HIDRAW slot in your LXD profile — or you can add a custom udev rule file to run it automatically.
If you save the above script as /usr/local/bin/add-fido-hidraw-devices-to-lxc-profile.sh, you can then add the below file as /etc/udev/rules.d/75-fido.rules (replacing justin with the username of your daily user) to automatically run the script for several different brands of FIDO security keys:
# Nitrokey 3 SUBSYSTEM=="hidraw", KERNEL=="hidraw*", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", RUN+="/bin/su justin -c /usr/local/bin/add-fido-hidraw-devices-to-lxc-profile.sh" # OnlyKey SUBSYSTEM=="hidraw", KERNEL=="hidraw*", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", RUN+="/bin/su justin -c /usr/local/bin/add-fido-hidraw-devices-to-lxc-profile.sh" # SoloKeys SUBSYSTEM=="hidraw", KERNEL=="hidraw*", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070|50b0|beee", RUN+="/bin/su justin -c /usr/local/bin/add-fido-hidraw-devices-to-lxc-profile.sh" # Yubico YubiKey SUBSYSTEM=="hidraw", KERNEL=="hidraw*", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0121|0200|0402|0403|0406|0407|0410", RUN+="/bin/su justin -c /usr/local/bin/add-fido-hidraw-devices-to-lxc-profile.sh"
Run the sudo udevadm control --reload-rules and sudo udevadm trigger commands to reload your udev rule files and trigger them for your currently plugged-in devices. If you use a different brand of security key, you can probably find its vendor and product IDs in the libfido2 udev rules file (or you can figure it out from the output of the udevadm info command).
No comments:
Post a Comment