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.