Intro

I recently set up an external graphics card paired with a micro PC for local Ollama experimentation. It’s been a while since I set up a new CentOS system and I wanted to be able to easily move my Yubikey between systems. I hit a snag in that the standard udev rules are (understandably) designed to only provide access to the user logged in at the console and I wanted to use my Yubikey via SSH.

Issues

The official Yubico documentation points to a very old set of documentation that is designed only for authenticating with a Yubikey. This is useful, but I want to be able to use mine to hold my GPG keys.

To get started with the CLI tooling, I snagged ykpers and ykclient from EPEL and attempted to make sure that things were working by running ykinfo -v.

Unfortunately, I was hit with a USB error: Access denied (insufficient permissions) error. I checked that the hardware was properly recognized by running sudo ykinfo -v and there were no issues.

Troubleshooting

Being from the 1900’s, I went down the traditional route of troubleshooting by checking logs and trying different methods. There wasn’t much in the logs that was suspicious so I attempted to log in via gdm and all was well.

I dropped the error into my favorite search engine and found many old articles regarding udev rules that were mostly focused on old Debian-based systems. (Granted, this isn’t a common use case)

I finally sighed and dropped the issue into Gemini using the following prompt:

Why am I seeing USB error: Access denied (insufficient permissions) when attempting to access my Yubikey using ykinfo when logged in via SSH and how do I fix it? I’m using CentOS 10 and want any solutions to respect good security practice while still allowing remote access.

Resolution

The answer provided by Gemini was generally correct and I wanted to make sure that more up to date information was in my online memory somewhere.

The default rules at /lib/udev/rules.d/69-yubikey.rules are:

ACTION!="add|change", GOTO="yubico_end"

# Udev rules for letting the console user access the Yubikey USB
# device node, needed for challenge/response to work correctly.

# Yubico Yubikey II
ATTRS{idVendor}=="1050",
ATTRS{idProduct}=="0010|0110|0111|0114|0116|0401|0403|0405|0407|0410", \
    ENV{ID_SECURITY_TOKEN}="1"

LABEL="yubico_end"

The issue that we’re running into is the ID_SECURITY_TOKEN which is set when logging in via gdm instead of allowing access to a group.

To ensure that we keep everything working properly for both gdm and remote access, we’ll set up a local yubikey-access group and extend the original file.

Unfortunately, we can’t easily extend udev rules, so we’ll need to create a new one.

The updated file should be placed in /etc/udev/rules.d/69-yubikey.rules with the following content:

ACTION!="add|change", GOTO="yubico_end"

# Udev rules for letting the console user access the Yubikey USB
# device node, needed for challenge/response to work correctly.

# Yubico Yubikey II
ATTRS{idVendor}=="1050",
ATTRS{idProduct}=="0010|0110|0111|0114|0116|0401|0403|0405|0407|0410", \
    OWNER="root", \
    GROUP="yubikey-access", \
    MODE="0660" \
    ENV{ID_SECURITY_TOKEN}="1"

LABEL="yubico_end"

After you save the file, you need to trigger the new rules:

sudo udevadm control --reload-rules
sudo udevadm trigger

Now add the yubikey-access group and add whatever users you like to the group:

sudo groupadd yubikey-access -U user1,user2,user3

You may need to either log back in or use newgrp yubikey-access to ensure that the new group is active for any user that is logged in.

Drawbacks

The biggest drawback to this approach is that the idProduct field won’t be updated alongside updates to the source file. This could be remedied using DNF post transaction actions (but I’m not bothering for the moment).