YubiKey Recovery#
Two physical keys exist. Their PIV/CA roles are inventoried in PKI maintenance → Hardware Reference; this page adds the other uses and what to do when a key is lost. The debugging log is raw notes, not a guide.
| Key | Serial | Kept | Roles |
|---|---|---|---|
| YubiKey 5C Nano (“nano5c”) | 23183421 | Home / safe | OpenPGP: git signing + SSH auth · FIDO2: LUKS on mokou, PAM U2F · PIV 9C: high-trust signing CA |
| YubiKey 5C NFC (“5cNFC”) | 24918246 | Keychain | OpenPGP: a separate identity, not provisioned in gpg · FIDO2: PAM U2F · PIV 9C: lower-trust signing CA |
Key × use matrix#
| Use | nano5c | 5cNFC | Works with no key? |
|---|---|---|---|
git commit signing (OpenPGP E48B9BA13823B0D8D065C1107467B45313F55526, modules/users/tsunami/git.nix) |
Yes — the only key in gpg’s keyring | No. Its OpenPGP identity (6E1A…1B96) was never imported (gpg --card-status → General key info: [none]); no pubkey on disk, no card URL |
Yes: commit.gpgSign = false since 2026-06-26 |
| SSH to fleet hosts (gpg-agent’s ssh-support serves the card’s auth key) | keys/id_nano5c.pub — authorized for tsunami, bcraton, and the darwin user on every host |
keys/id_5cNFC.pub — authorized alongside it in the same three user modules |
Yes: ~/.ssh/id_ed25519; for GitHub also the sops github/ssh-key (ssh.nix identity order) |
| PAM U2F (login, sudo, kscreenlocker) | Registered | Registered — four es256 credentials in modules/users/tsunami/yubikey.nix across the two keys (TODO(owner): which credential belongs to which key) |
Yes: pam_u2f is sufficient + nouserok, so the password always works. No recovery needed |
LUKS FIDO2 — mokou / and /nix (luks, luks-nix partlabels) |
Enrolled by scripts/luks-enroll-yubikeys.sh (FIDO2 only; whichever key was plugged in) |
TODO(owner): enrolled too? |
TODO(owner): is a passphrase keyslot enrolled? Check with cryptsetup luksDump /dev/disk/by-partlabel/luks. The initrd waits forever (x-systemd.device-timeout=0), so a passphrase can be typed if one exists |
LUKS FIDO2 — mokou /data (cryptdata) |
fido2-device=auto |
TODO(owner) |
TODO(owner): passphrase slot? |
LUKS — mokou /pool (cryptpool0/1) |
Recovery slot | — | Yes: the keyfile /etc/luks/pool.key on the encrypted root unlocks it at boot; FIDO2 and a passphrase are recovery slots only; the passphrase is in Bitwarden |
LUKS — shinobu (two volumes in hardware-configuration.nix) |
Not used | Not used | Passphrase only |
| PIV signing CAs (slot 9C) | High-trust CA | Lower-trust CA | The root key is in pki/db/FalseBlue-CA.xdb.sops; see If the Root Key is Lost |
If the nano5c is lost#
- You can still log in. Password login works everywhere (PAM), and SSH falls back to the 5cNFC (authorized) or the on-disk keys.
- LUKS on mokou. If a passphrase slot exists, type it at the prompt. If it does not, the root disk is unrecoverable without the key: reinstall and restore. Then enrol the replacement key and a passphrase (below) before anything else.
- git signing already tolerates the loss (
gpgSign = false). To sign again, either import the 5cNFC’s public key and pointuser.signingKeyat6E1A…1B96(TODO(owner): where is that pubkey — a backup or a keyserver?), or generate a new OpenPGP key on the replacement, export its pubkey tomodules/users/tsunami/keys/gpg-tsunami.asc, and updategit.nix. - SSH key replacement. Export the new card’s auth key
(
gpg --export-ssh-key <keyid>), replacemodules/users/tsunami/keys/id_nano5c.pub(consumed bymodules/users/tsunami/ssh.nix,modules/users/tsunami/default.nix,modules/users/bcraton/default.nix,modules/users/tsunami-darwin/default.nix), build, and deploy every host while the old fallback still works. - Revoke. Remove the lost key’s U2F credential from
yubikey.nix, wipe its LUKS slot (systemd-cryptenroll --wipe-slot=fido2 <device>, then re-enrol the remaining key), and revoke its PIV CA certificate per Updating CRLs.
If the 5cNFC is lost#
Nothing stops working: it signs no commits, SSH prefers the nano5c, and PAM has
a password fallback. Remove its U2F credential from yubikey.nix and revoke
its PIV CA certificate (it is the lower-trust CA precisely because it
travels). Issue a replacement CA per
Renewing a YubiKey CA Cert.
Re-enrolment commands#
# PAM U2F: register a key (add `-n` for an additional key), then merge the
# output onto the single `tsunami:` line in modules/users/tsunami/yubikey.nix
pamu2fcfg -o pam://tsunaminoai -i pam://tsunaminoai
# LUKS FIDO2 on mokou (root + nix); run as root with the key plugged in
scripts/luks-enroll-yubikeys.sh
# Add a passphrase slot next to FIDO2 — the only no-hardware path
systemd-cryptenroll /dev/disk/by-partlabel/luks --password
systemd-cryptenroll /dev/disk/by-partlabel/luks-nix --password
# Inspect slots
cryptsetup luksDump /dev/disk/by-partlabel/luks
# SSH public key from the card's OpenPGP auth subkey
gpg --export-ssh-key E48B9BA13823B0D8D065C1107467B45313F55526
Related#
- PKI maintenance — the CA roles, slot reference, root-key loss.
- mokou — disk layout and the
/poolrecovery design. - Accounts & Credentials — Bitwarden, where the passphrases live.
- Successor Handbook