SSH¶
Recipes for managing FIDO2/YubiKey SSH keys and testing host configurations.
Background¶
Multiple accounts on the same hostname (e.g. two GitHub accounts) require SSH host aliases — each alias maps to a
specific key via IdentitiesOnly. Without this, SSH offers all available keys and may authenticate as the wrong
account. See ~/.ssh/config for the full configuration and comments explaining each directive.
On macOS, the built-in /usr/bin/ssh lacks FIDO2 support. These recipes use Homebrew's OpenSSH which is compiled with
libfido2. On Linux, the system SSH works natively.
New Machine Setup¶
After chezmoi init --apply, the SSH config is in place but no key stubs exist yet. For each YubiKey:
- Plug in the YubiKey
just ssh download— pulls all resident key stubs from that keyjust ssh test <host>— verify each host alias works- Swap to next YubiKey, repeat
That's it. The config lists all key files; SSH skips any that don't exist.
Adding a New Account¶
To add SSH access to a new service (e.g. a new git host or server):
- Plug in the YubiKey
just ssh generate <user>_<service> <yubikey>— creates the key- Add the
.pubkey to the service - Repeat for each YubiKey that needs access
- Add a
Hostblock to~/.ssh/config(and the chezmoi template) just ssh test <host>— verify
Naming Convention¶
Key names follow <user>_<service>_<yubikey>:
bluefing_github_nano— GitHub personal, nano YubiKeyfungible_codeberg_primary— Codeberg personal, primary YubiKeywork_github— work GitHub (single YubiKey, no suffix needed)
The application field (ssh:<name>) stored on the YubiKey determines the filename when downloaded via
just ssh download on any machine: ssh:bluefing_github_nano → id_ed25519_sk_rk_bluefing_github_nano.
Key Management¶
generate <application> <yubikey> creates a new FIDO2 resident key on the plugged-in YubiKey. Shows the full command
for review before proceeding. See just ssh show generate for detailed parameter docs.
download pulls FIDO2 resident key stubs from a plugged-in YubiKey into ~/.ssh. Each YubiKey stores its own set of
resident credentials — swap the key and run again to download from a different one. You'll be prompted for the YubiKey
PIN and may need to touch the key. Use this on new machines to get key stubs without regenerating.
The downloaded files are stubs (key handles + public key), not private keys. The actual private key never leaves the YubiKey hardware.
keys shows all FIDO2 key stubs currently in ~/.ssh.
fingerprint <key> shows the fingerprint for a specific key stub. Pass the filename or use -i to pick interactively
via fzf.
YubiKey¶
yk-info shows the plugged-in YubiKey's model, serial number, and FIDO2 resident credentials. Use this to identify
which physical key you're holding — the credential names (e.g. ssh:fungible_codeberg_primary) tell you.
Testing¶
test <host> runs ssh -T against a host alias from your config (e.g. just ssh test github-personal). GitHub
responds with the authenticated username — use this to verify the right key hits the right account. Only the currently
plugged-in YubiKey's hosts will work.
debug <host> shows verbose SSH connection output. Use this when authentication fails — it shows which key was offered,
whether ControlMaster reused a socket, and where things went wrong.
Sockets¶
ControlMaster multiplexes SSH connections to avoid repeated YubiKey auth for the same host. Sockets are per host alias
(using %n), so github-personal and github-work never share a socket despite both connecting to github.com.
sockets lists active control sockets in ~/.ssh/sockets/.
kill-socket <host> closes a multiplexed connection. Use this if a socket gets stuck or if you need to force
re-authentication (e.g. after swapping YubiKeys).
Gotchas¶
downloadwrites key stubs to~/.sshregardless of your current directory.- If
testauthenticates as the wrong user, checksocketsfirst — a stale multiplexed connection is the most likely cause. Kill it withkill-socketand retry. - macOS: if
downloadsays "Cannot download keys without provider", you're using the systemssh-keygen. Ensureopensshandlibfido2are installed via Homebrew. - SSH skips missing key stubs silently. If a YubiKey's stubs haven't been downloaded yet, those entries are just ignored.