How to Set Up USB Device Whitelisting (USBGuard) on Fedora

USBGuard lets you control which USB devices are allowed to connect to your Fedora system by enforcing a policy file that explicitly whitelists trusted hardware.

You plugged in a USB drive and it vanished

You are at a coffee shop. You plug in a USB-C hub to connect an external monitor. The screen stays black. Your keyboard stops responding. You panic. The system did not crash. USBGuard just caught a device that was not on the approved list and cut power to the bus. This happens more often than you expect when you enable strict USB whitelisting without a safety net. A botched policy can leave you unable to type a recovery command. Run this from a backup VM first if you can.

What USBGuard actually does

USBGuard is not a firewall for network traffic. It is a kernel-space policy engine that talks to the USB subsystem through usbmon and udev. When a device connects, the kernel reports its descriptors. USBGuard intercepts that report, compares it against your policy file, and tells the kernel whether to attach the device or drop it. Think of it like a building security desk. The desk does not care what you do inside. It only checks your badge against the guest list before handing you the keycard. If the badge is missing or mismatched, the door stays locked.

The daemon runs in userspace, but it pushes rules down to the kernel so the enforcement happens before any driver loads. This means malicious firmware, rubber ducky keystroke injectors, and unauthorized storage drives never get a chance to execute. The policy file defines exactly which vendor IDs, product IDs, serial numbers, and device names are permitted. Everything else gets blocked at the hardware level.

Run journalctl -xeu usbguard first. Read the actual error before guessing.

Install and generate a safe baseline policy

You need to install the package and create a policy before you enable the service. Starting the daemon without a policy blocks every USB device on the system. That includes your keyboard, mouse, and internal USB controllers. You will be staring at a frozen desktop with no way to type a recovery command.

Run the installation command first.

sudo dnf install usbguard
# WHY: Pulls the daemon, CLI tools, and default policy skeleton from the Fedora repository.
sudo systemctl enable usbguard
# WHY: Registers the service with systemd so it starts on boot, but does not run it yet.

Generate a policy from the hardware currently attached to the machine.

sudo usbguard generate-policy | sudo tee /etc/usbguard/rules.conf
# WHY: Scans active USB buses, extracts vendor/product IDs and serial numbers, and writes allow rules.
# WHY: Piping to tee preserves root ownership and correct permissions on the policy file.

Review the output before proceeding. The file contains one rule per line. Each rule specifies a verdict, a device ID, a serial number, and a human-readable name. If you see a rule for a device you do not recognize, remove it now. The policy file lives in /etc/usbguard/rules.conf. Never edit the template in /usr/lib/usbguard/. Files in /usr/lib/ ship with the package and get overwritten on updates. Your changes in /etc/ survive upgrades.

Snapshot the system before the upgrade. Future-you will thank you.

Start enforcing and verify the rules

Once the policy reflects your actual hardware, start the daemon.

sudo systemctl start usbguard
# WHY: Launches the userspace daemon and pushes the current policy to the kernel.
sudo systemctl status usbguard
# WHY: Confirms the service is active, shows recent log lines, and catches startup errors immediately.

Check the active rules and connected devices.

sudo usbguard list-devices
# WHY: Queries the kernel for every attached USB device and shows the current policy verdict.

The output lists each device with a numeric ID, a verdict of allow or block, and the full descriptor string. Devices that match your policy show allow. Anything new shows block. The daemon does not unplug devices that were already attached before it started. It only enforces on new connection events. Internal devices like fingerprint readers, Wi-Fi cards, and touchpads often appear as USB devices. If you block them, you lose functionality. Verify every internal component is whitelisted before you walk away from the machine.

Reboot before you debug. Half the time the symptom is gone.

Manage devices on the fly and permanently

You will occasionally need to test a new peripheral or grant temporary access to a colleague's drive. The CLI lets you change verdicts without touching the policy file.

Allow a device temporarily.

sudo usbguard allow-device 5
# WHY: Changes the kernel verdict for device ID 5 to allow for the current session.
# WHY: The change disappears after a reboot or a policy reload.

Block a device immediately.

sudo usbguard block-device 5
# WHY: Cuts power and detaches the device from the USB bus at the kernel level.

Promote a temporary allow to a permanent rule.

sudo usbguard allow-device -p 5
# WHY: Appends a matching allow rule to /etc/usbguard/rules.conf so it survives reboots.

You can also write rules manually. Copy the exact descriptor line from usbguard list-devices, change the verdict to allow, and paste it into the policy file.

# /etc/usbguard/rules.conf
allow id 0781:5583 serial "4C530001234" name "SanDisk Ultra"
# WHY: Explicitly whitelists a specific flash drive by vendor, product, and serial number.

Reload the policy without restarting the daemon.

sudo usbguard reload-policy
# WHY: Re-reads the configuration file and updates the kernel rules in place.

Trust the package manager. Manual file edits drift, snapshots stay.

Configure IPC access and audit logs

By default, only the root user can run usbguard commands. The daemon uses a Unix domain socket for inter-process communication. You can grant controlled access to other users or groups.

Add group permissions for the wheel group.

sudo usbguard add-user -g wheel --devices=list,allow,block --policy=list
# WHY: Creates an IPC access rule that lets wheel members query devices and change verdicts.
# WHY: Restricts policy editing to root, preventing accidental rule corruption.

Monitor blocked connection attempts in real time.

journalctl -xeu usbguard
# WHY: Streams the daemon logs with explanatory context and jumps to the end of the buffer.

Blocked devices print a clear line showing the vendor ID, product ID, and serial number. Use that information to decide whether to whitelist the device or report it as unauthorized. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. USBGuard ships with a proper SELinux policy, so you rarely need to adjust contexts.

If you see [FAILED] Failed to start usbguard.service during boot, your network configuration probably references a missing interface name. In this case, the policy file contains a malformed rule or incorrect permissions. Check the journal for the exact parser complaint. Fix the syntax and restart the service. Never force-start a broken policy.

Run journalctl first. Read the actual error before guessing.

Common pitfalls and what the error looks like

The most frequent mistake is generating the policy while a docking station or external GPU is connected, then removing it later. USBGuard will block the next device that tries to use that port because the serial number no longer matches. Run usbguard generate-policy with only the core peripherals attached. Keep the policy lean.

Another trap is editing the policy file with a graphical editor that changes line endings or adds invisible characters. The parser fails silently and drops the rule. Use nano, vim, or sed for edits. Verify the syntax by reloading the policy and checking the journal for parse errors.

The usbguard daemon will refuse to proceed and print Error: Failed to parse policy file: Invalid rule syntax at line 14. The error is intentional. Read the next paragraph before forcing. Line 14 usually contains a missing quote, a stray space, or a Windows-style carriage return. Strip the bad character and reload.

If you lock yourself out completely, you can recover through the emergency shell. Press Ctrl+Alt+F3 to drop to a TTY. If your keyboard is blocked, you will need to boot with systemd.unit=rescue.target appended to the kernel parameters in GRUB. Disable the service, fix the policy, and reboot.

If the boot menu is gone, GRUB rescue is your friend, not your enemy.

When to use USBGuard vs alternatives

Use USBGuard when you need strict, kernel-level enforcement of which physical devices can attach to the system. Use udev rules when you only want to change permissions or mount options for known devices. Use systemd socket activation when you want to launch a service only when a specific USB device appears. Stay on standard udev if you only need to auto-mount drives or trigger scripts on connection. Use USBGuard when you are running a kiosk, a corporate laptop, or a public terminal where unauthorized storage or debug tools must be physically blocked.

Where to go next