[HOWTO] Smartcard passthrough for SSH in Fedora WSL

Most guides I found regarding the use of security tokens in WSL guests resort to using named pipes, with npiperelay.exe on the Windows host side and socat on the Linux guest side, with ssh-agent thrown into the mix to pass secrets. That setup works, but it leaves the token open for authentication, whereas I wanted a more native experience in which, both in Windows and Linux, I am asked every time for a PIN, in the case of a smartcard, to unlock it.

This HOWTO explains how to pass the hardware from the host to the guest so it can use it exclusively, as it would on a non-VM host. For those less familiar with virtualisation, please note that passthrough means the hardware is not available to the host while it is being passed to the guest. That can be controlled, but more on that later.

Phase 1: Windows host setup

1. Install usbipd-win: Download here.

2. Identify hardware and bind: in PowerShell, run as Administrator:

# Find your reader's / token's ID (e.g., 2ce3:9563)
usbipd list

# Bind it to the shared pool (only needed once)
usbipd bind --hardware-id 2ce3:9563

Phase 2: Fedora WSL guest

1. Define the Polkit rule: WSL is a “headless” session. Fedora’s default policy blocks non-console users from accessing hardware. Create this override:

sudo nano /etc/polkit-1/rules.d/10-smartcard.rules
polkit.addRule(function(action, subject) {
    if (action.id == "org.debian.pcsc-lite.access_pcsc" || 
        action.id == "org.debian.pcsc-lite.access_card") {
        return polkit.Result.YES;
    }
});

2. Install the stack:

sudo dnf install opensc pcsc-lite pcsc-lite-ccid
sudo systemctl enable --now pcscd

Phase 3: choose your workflow

Decide whether you want the card to be “always on” in Fedora, or toggled manually from Windows.

Option A: automation.

Use systemd to attach the card reader automatically whenever Fedora starts.

A1. Create the script: check the Windows mount point and use your hardware ID.

sudo nano /usr/local/bin/attach-card-reader.sh
#!/bin/bash
if ! lsusb | grep -q "2ce3:9563"; then
    # Runs the attach command in the background via Windows
    /mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -Command "Start-Process usbipd -ArgumentList 'attach --wsl --hardware-id 2ce3:9563' -WindowStyle Hidden" > /dev/null 2>&1
fi
sudo chmod 755 /usr/local/bin/attach-card-reader.sh

A2. Create and enable the service:

sudo nano /etc/systemd/system/attach-card-reader.service
[Unit]
Description=Attach Smartcard reader via usbipd
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/attach-card-reader.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
sudo systemctl enable attach-card-reader.service

Option B: manual control through PowerShell functions.

If you prefer to keep the card on Windows until you specifically need it for Fedora, add these functions to your Windows PowerShell Profile.

B1. Edit $PROFILE: in PowerShell, run notepad $PROFILE to add these functions, using your hardware ID.

function card-on {
    usbipd attach --wsl --hardware-id 2ce3:9563
}

function card-off {
    usbipd detach --hardware-id 2ce3:9563
}

B2. Attach / detach at will: type card-on or card-off in any Windows terminal to move the hardware.

Phase 4: verification

1. Refresh: in PowerShell, if using Option A, run wsl --shutdown. If Option B, just run card-on.

2. Test in Fedora:

opensc-tool -l

You should see your card reader or security token listed, without needing sudo.

3. SSH integration: add this, or whatever you would normally add to your ~/.ssh/config on a non-VM host, for the card or token to work:

PKCS11Provider /usr/lib64/pkcs11/opensc-pkcs11.so