Qubes OS

Automatically attaching a YubiKey to a Qubes OS vault for GPG

Use Qubes OS device assignments to automatically attach a YubiKey to your vault qube for GPG use, avoiding the need to manually reattach it every time you plug it in.


I learned a useful Qubes OS trick recently that saves me a small but repetitive step every time I plug in my YubiKey.

My setup has a YubiKey containing my GPG keys, with the USB device normally exposed by sys-usb. I want the YubiKey available inside my vault qube so that GPG can use its OpenPGP smart-card interface.

Until now, every time I plugged the YubiKey in, I would run something like this in dom0:

DEVICE=$(qvm-usb list | grep -i Yubikey | awk '{print $1}')

qvm-usb attach vault "$DEVICE"

Without doing that, attempting an operation requiring the private key would result in GPG asking me to insert the card:

Please insert the card with serial number ...

After attaching the USB device to vault, GPG could see the YubiKey and everything worked.

This was fine, but I had assumed that manually attaching the device every time was simply how USB passthrough in Qubes worked.

It turns out Qubes can remember the assignment.

Attachment versus assignment

The useful distinction is between attaching and assigning a device.

When I run:

qvm-usb attach vault "$DEVICE"

I am attaching the currently connected USB device to vault.

That is temporary. If I unplug the YubiKey, that particular attachment disappears. The next time it is inserted, it is once again available through the USB qube rather than automatically being handed to vault.

Qubes also has the concept of a device assignment.

An assignment tells Qubes that when a matching device appears in the future, it should automatically be attached to a particular qube.

So instead of repeatedly running attach, I can plug in my YubiKey once and run just once:

DEVICE=$(qvm-usb list | grep -i Yubikey | awk '{print $1}' | head -1)

qvm-usb assign --device vault "$DEVICE"

That is now a persistent configuration, rather than a one-off attachment.

Now I can unplug the YubiKey and plug it back in later and Qubes will automatically attach it to vault.

Why --device?

There is an important detail in the command:

--device

Without it, a Qubes USB assignment can be associated with both the device and the USB port where it was connected.

For example:

qvm-usb assign vault "$DEVICE"

is useful if I deliberately want the assignment tied to that physical USB connection.

In my case, however, I want:

Whenever this YubiKey appears, attach it to vault.

I don't particularly care which USB socket I used.

So:

qvm-usb assign --device vault "$DEVICE"

tells Qubes to base the automatic assignment on the identity presented by the device rather than its current USB port.

The practical result is:

YubiKey plugged in
sys-usb detects it
Qubes finds its saved device assignment
USB device automatically attaches to vault
GPG can see the YubiKey/OpenPGP smart card

Checking the assignment

Assignments can be displayed with:

qvm-usb list --assignments

Qubes marks assigned qubes separately from devices that are merely attached at that moment.

After reconnecting the YubiKey, a normal:

qvm-usb list

should show it as being used by vault, without having to manually run qvm-usb attach.

What about --persistent mode?

Another potentially confusing option is --persistent on qvm-usb attach.

It sounds like exactly what is needed here, but it isn't quite the same thing.

The modern Qubes device model distinguishes a normal automatic assignment from a required device.

A required device is expected to be available when the target qube starts. If it isn't available, that can prevent the qube from starting.

That is not what I want for a hardware token which normally remains unplugged until I need it.

A normal:

qvm-usb assign --device vault "$DEVICE"

means, effectively:

If this device appears, automatically attach it to vault.

It does not mean:

vault must have this device in order to start.

That's a much better fit for a YubiKey.

Removing the assignment

If I later decide that I no longer want the YubiKey automatically attached to vault, I can plug it in, identify it again and remove the assignment:

DEVICE=$(qvm-usb list | grep -i Yubikey | awk '{print $1}' | head -1)

qvm-usb unassign --device vault "$DEVICE"

A manual detach and an unassign are different operations just as attach and assign are.

Detaching changes what is connected now.

Unassigning removes the rule governing what should happen in the future.

A small security consideration

Automatic USB assignment is worth thinking about before enabling it for a high-value qube.

The device identity used for matching ultimately comes from information presented by the USB device itself. Device identification should therefore not be treated as equivalent to cryptographic authentication of a particular physical YubiKey.

If I wanted a stricter setup, I could omit --device:

qvm-usb assign vault "$DEVICE"

and deliberately associate the assignment with the particular USB port as well.

There is a trade-off here between convenience and how broadly the automatic assignment should match.

For my setup, where the YubiKey is specifically intended for the vault qube, matching the device regardless of port is the useful behaviour.


It's a very small Qubes feature, but one I wish I'd known about earlier!

At a glance
  • Runs in: dom0
  • Device: YubiKey attached through a USB qube such as sys-usb
  • One-off attachment: qvm-usb attach vault DEVICE
  • Persistent assignment: qvm-usb assign --device vault DEVICE
  • Behaviour: automatically attaches the YubiKey to vault when it is plugged in
  • Remove assignment with: qvm-usb unassign --device vault DEVICE
Need help securing or automating a Qubes OS workflow?
I do contract sysadmin, security and privacy-infrastructure work, and previously sysadminned the Qubes OS onion apt/yum repositories. I also built CI and workflow tooling for SecureDrop Workstation on Qubes OS. Let's talk compartmentalisation!
Contact me