aniketd

The hybrid Yubikey setup

Aniket Shirish Deshpande April 04, 2026

The Strategy:

SSH relies on FIDO2 (HID). Sudo/PAM relies on OTP (HID). File encryption relies on PIV (Smart Card). We run pcscd via socket-activation strictly to support age-plugin-yubikey, eliminating daemon conflicts and hardware lockups while keeping best-in-class tools.

Factory default credentials

FIDO2 has no defaults. But, PIV requires these to initialize:

Configure all your yubikeys at once

Plug in both primary and backup keys simultaneously to ensure exact mirror provisioning.

# List connected keys & serials
ykman list

# Prepend all commands with device target serial
ykman --device 12345678 [command]

Provisioning

Execute sequentially on both keys.

Initialise PIV

# 1. Gen new Management Key (requires touch)
ykman --device [SERIAL] piv access change-management-key --generate --touch
# ^^^ SAVE OUTPUT TO PASSWORD MANAGER! ^^^

# 2. Change PIN & PUK (prompts for defaults)
ykman --device [SERIAL] piv access change-pin
ykman --device [SERIAL] piv access change-puk

Enforce “touch”

# 1. Set FIDO2 PIN (limit 63 chars)
ykman --device [SERIAL] fido access change-pin

# 2. Force PIN+touch for all passkeys
ykman --device [SERIAL] fido config toggle-always-uv

# 3. Force touch for PIV Auth (slot 9a)
ykman --device [SERIAL] piv set-touch 9a always

# 4. Force touch for PIV signing (slot 9c)
ykman --device [SERIAL] piv set-touch 9c always

Install shared PAM seed on slot-2 (optional)

Do not use --generate if you want your backup key to unlock your OS. Generate it manually and apply it to both.

# 1. Generate a secure 40-character hex seed offline
SEED=$(openssl rand -hex 20)
echo "Save this seed to your password manager: $SEED"

# (Alternative: rbw generate 40 --no-symbols if you prefer your PM CLI)

# 2. Program identical seed into both keys
ykman --device [PRIMARY_SERIAL] otp chalresp 2 $SEED --touch
ykman --device [BACKUP_SERIAL] otp chalresp 2 $SEED --touch

Reduce potential attack surface

# Disable unused physical interfaces
ykman --device [SERIAL] config nfc --disable-all
ykman --device [SERIAL] config usb --disable OPGP

# Lock config against tampering
ykman --device [SERIAL] config set-lock-code --generate
# ^^^ SAVE THIS TO PASSWORD MANAGER! ^^^

NixOS configuration

Core configuration (configuration.nix, or flake.nix)

# 1. Socket-activated smart card daemon (only runs when 'age' calls it)
services.pcscd.enable = true;

# 2. User-space USB access
services.udev.packages = [ pkgs.yubikey-personalization ];

# 3. PAM Yubico (challenge-response)
security.pam.yubico = {
  enable = true;
  debug = false;
  mode = "challenge-response";
};

# 4. Enforce hardware touch for sudo
security.pam.services.sudo.yubicoAuth = true;

# 5. Core system packages
environment.systemPackages = with pkgs; [
  yubikey-manager
  pam_yubico
  age
  age-plugin-yubikey
];

Workflows

OS sudo authentication (OTP)

Run once to link your user account to the challenge-response seed.

mkdir -p ~/.yubico
# Queries slot 2 and saves challenge file
ykpamcfg -2 -v

SSH authentication (FIDO2)

Modern resident keys. Private key stays on hardware.

# Generate key (-O resident stores it on YubiKey)
ssh-keygen -t ed25519-sk -O resident -O verify-required -C "some@identity"

# Download public stub to a new machine. This is REQUIRED only every new machine only once.
ssh-keygen -K

File encryption (age-plugin-yubikey via PIV)

Initializes the PIV module for age. Run this for both primary and backup keys.

# Interactive setup (requires PIV PIN and Management Key)
# Make sure to say YES to requiring a physical touch!
age-plugin-yubikey --generate

# Retrieve your public identity later (if you lose it)
age-plugin-yubikey --identity

# Encrypt a file to multiple keys (so both primary and backup can decrypt)
age -r age1yubikey1_PRIMARY -r age1yubikey1_BACKUP -o secret.age secret.txt

# Decrypt (YubiKey will flash, tap to authorize)
age -d -i ~/.config/age/yubikey-identity.txt secret.age

Auditing and recovery

ActionTargetTerminal command
Audit PasskeysFIDO2 (100 (or older firmware has 25) slots)ykman fido credentials list
Audit PIV CertsSmart Card (24 slots)ykman piv info
Factory Wipe FIDO2Destroys passkeys & SSHykman fido reset (8 failed PIN tries permanently locks FIDO2)
Recover/Wipe PIVResets smart cardykman piv access unblock-pin OR ykman piv reset