A normal SSH private key is a file. Malware, a stolen laptop backup or a careless copy can take it. With a hardware security key (YubiKey, SoloKey, Nitrokey, Google Titan or any FIDO2 key), the private key never leaves the device. Every login needs the physical key plugged in, and usually a touch. OpenSSH supports this natively since version 8.2.

Requirements

  • Client: OpenSSH 8.2+ (Linux, macOS 13+ with the system OpenSSH or Homebrew, Windows OpenSSH 8.9+ or WSL), with libfido2.
  • Server: OpenSSH 8.2+ (Ubuntu 20.04+, Debian 11+, RHEL 9 and every current distribution).
  • Key: any FIDO2/U2F security key. Ed25519 support needs FIDO2 firmware with Ed25519 (most current keys). Otherwise use ECDSA.
ssh -V

1. Create a hardware-backed key

Plug in the security key, then run:

ssh-keygen -t ed25519-sk -C "alice yubikey"
# fallback for keys without Ed25519: ssh-keygen -t ecdsa-sk

Touch the key when it blinks. This creates:

  • ~/.ssh/id_ed25519_sk — not the real private key, but a “key handle” that only works together with the physical device;
  • ~/.ssh/id_ed25519_sk.pub — the public key, which goes on servers as usual.

Even if someone copies the id_ed25519_sk file, it’s useless without your hardware key.

Options

ssh-keygen -t ed25519-sk -O resident -O verify-required -O application=ssh:work -C "alice yubikey"
  • -O resident — store the key handle on the device. On a new computer, restore it with ssh-keygen -K. That’s handy, but anyone with the device (and its PIN) can also extract the handle.
  • -O verify-required — require the FIDO2 PIN as well as touch. That gives two factors: something you have plus something you know.
  • -O no-touch-required — skip the touch, for automation. This weakens protection, and the server must allow it explicitly.

2. Install the public key on servers

ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub user@server

Or append the .pub content to ~/.ssh/authorized_keys on the server. Then log in:

ssh user@server
# Confirm user presence for key ED25519-SK …  → touch the key

3. Have a backup key

If your only security key is lost or broken, you’re locked out. Register at least two hardware keys: create an -sk key with each, and put both public keys on every server. Keep the backup key somewhere safe.

Keep an emergency path too: your provider’s VNC console, plus a strong password for console login.

4. Optionally require hardware keys on the server

To allow only security-key logins for certain users, restrict the accepted key types:

# /etc/ssh/sshd_config.d/30-sk.conf
Match User admin
    PubkeyAcceptedAlgorithms [email protected],[email protected]

Require PIN verification for keys in authorized_keys:

verify-required [email protected] AAAA… alice yubikey

Reload sshd, and test in a new session before closing the old one.

Using a new computer: resident keys

If you created the key with -O resident:

cd ~/.ssh
ssh-keygen -K            # downloads key handles from the device (asks for PIN)
mv id_ed25519_sk_rk_* id_ed25519_sk      # rename if you like

Git and other tools

  • GitHub and GitLab accept sk-ssh-ed25519 keys for Git over SSH. Add the .pub as usual, and every push or pull needs a touch. See Git SSH keys.
  • Git commit signing with SSH keys works with -sk keys too.
  • Agent forwarding works, but every use requires a touch on your device, which is a nice safety property.

Alternative: YubiKey PIV or OpenPGP

Before FIDO2 support, YubiKeys were used for SSH through PIV (PKCS#11) or the OpenPGP applet with gpg-agent. These still work, and support RSA keys for very old servers, but setup is more involved. For any OpenSSH 8.2+ server, -sk keys are simpler.

Troubleshooting

  • Key enrollment failed: requested feature not supported — the key’s firmware lacks Ed25519. Use ecdsa-sk.
  • No FIDO SecurityKeyProvider specified, or the device isn’t found — libfido2 is missing, or (on Linux) udev rules don’t give your user access. Install libfido2-1 or your distribution’s yubikey udev package. In WSL, USB pass-through needs extra setup.
  • The server rejects the key — the server’s OpenSSH is older than 8.2, or the algorithm isn’t allowed. Check ssh -v output.
  • Touch prompt doesn’t appear in GUI tools — use a terminal, or configure SSH_ASKPASS.

Quick reference

Task Command
Create key ssh-keygen -t ed25519-sk
With PIN + resident -O verify-required -O resident
Install on server ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub user@host
Restore resident keys ssh-keygen -K
Require PIN (server) verify-required option in authorized_keys

Related: SSH certificates and SSH two-factor authentication.

  • SSH
  • Security
  • Hardware