SSH Multi-Factor Authentication with SoloKey V2

Improving SSH security a second factor at a time

In a bout of attempting to improve my operational security, I decided to review my current practices and see which areas I could improve. While I already use SSH keys for auth, having a file that is essentially a password to all my servers is a bit of a security risk if it ever is compromised. I already use my SoloKey for 2FA on various websites, so why not for SSH too? This way, even if someone gets my private key file, they can't access my servers without physically having my SoloKey. Still a risk (see the XKCD comic about a $5 wrench), but less so.

Editor's Note: While MFA by using a physical key is a great improvement, you really should look into using SSH Certificates as they are time scoped, and depending on how you have them set up, have automatic rotation. Among other benefits, this is a great way to ensure that even if a key is unknowingly compromised, it can't be used for long.

Also, this same process could be used for other physical keys like YubiKeys, but I have several SoloKeys V2 (cheaper and open-source) so that is what I used.

OpenSSH support on macOS

Creating the key starts with ssh-keygen -t ed25519-sk and touching the SoloKey when prompted. On the macOS devices I tested, the bundled SSH version did not support this key type, so I installed a newer version of OpenSSH:

brew install openssh libfido2

After installation, you can check that you have the right version:

ssh -V

You should see OpenSSH_8.2 or later, which supports the FIDO2 keys. If you don't, then you may need to update your $PATH environment variable to point to the Homebrew version of SSH.

Creating a key tied to your SoloKey

With the newer OpenSSH installed, create the key:

ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk

You'll be asked for a passphrase (recommended), and be prompted to touch your SoloKey to confirm. Once done, you'll have two new files:

  • ~/.ssh/id_ed25519_sk - your private key
  • ~/.ssh/id_ed25519_sk.pub - your public key

Making it convenient

For convenience, I added the key to my SSH agent:

ssh-add ~/.ssh/id_ed25519_sk

If you don't use the SSH agent, you could instead add the key to your SSH configuration file

vi ~/.ssh/config
# Use the security key for all connections
Host *
    IdentityFile ~/.ssh/id_ed25519_sk

Setting up the server side

Similarly to how you would add a regular SSH key, you can add the public key to your server:

cat ~/.ssh/id_ed25519_sk.pub | pbcopy
ssh user@remote-server "vi ~/.ssh/authorized_keys" # Paste the public key and save

Just like with your local machine, you'll need to make sure the remote server also supports the new key type. You can check this by running:

ssh user@remote-server "ssh -V"

The moment of truth

Now try connecting:

ssh user@remote-server

If everything's set up correctly, you'll be prompted to touch your SoloKey to authenticate.

The older OpenSSH version bundled with macOS was the only setup problem I hit. The same key can also authenticate to other services, including Gitea.

If you are on a Mac, you could also look into Secretive, which stores SSH keys in the Secure Enclave and integrates with Touch ID.