Skip to content

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:

  1. Plug in the YubiKey
  2. just ssh download — pulls all resident key stubs from that key
  3. just ssh test <host> — verify each host alias works
  4. 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):

  1. Plug in the YubiKey
  2. just ssh generate <user>_<service> <yubikey> — creates the key
  3. Add the .pub key to the service
  4. Repeat for each YubiKey that needs access
  5. Add a Host block to ~/.ssh/config (and the chezmoi template)
  6. just ssh test <host> — verify

Naming Convention

Key names follow <user>_<service>_<yubikey>:

  • bluefing_github_nano — GitHub personal, nano YubiKey
  • fungible_codeberg_primary — Codeberg personal, primary YubiKey
  • work_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_nanoid_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

  • download writes key stubs to ~/.ssh regardless of your current directory.
  • If test authenticates as the wrong user, check sockets first — a stale multiplexed connection is the most likely cause. Kill it with kill-socket and retry.
  • macOS: if download says "Cannot download keys without provider", you're using the system ssh-keygen. Ensure openssh and libfido2 are installed via Homebrew.
  • SSH skips missing key stubs silently. If a YubiKey's stubs haven't been downloaded yet, those entries are just ignored.