This time, I’m going over how I now handle SSH keys. It involves OpenSSH certificates! And YubiKeys! Yaaay cryptography!
First, a little background. Did you know that you can sign SSH keys using a central authority and have them just work, without being added to the authorized_keys
file?
Even then, it would normally be a pain in the rear to have that work in a way that didn’t result in moving public keys all over the place.
Enter the Yubikey. This little guy can be a CA in your pocket! Albeit, only the fancy keys that support the PIV application can do this, so it’s a little bit of a pricy solution. But a fairly simple and secure one. I think smart cards can also techincally do this, but I’ve not read up on those.
So, with these ingredients, the setup for a new SSH client can be as simple as installing the yubico-piv-tool
package (or the equivelent on that system), generating a key with ssh-keygen
and finally signing said key, again with ssh-keygen
.
With as little as that, I can be logged in to any of my servers that have the Yubikey’s CA public key installed! No fumbling around with trying to move private keys about, no copying of the public key to an authorized machine for upload, just generate, sign, log in!
This method also has great support for storing the key in a TPM or the Secure Enclave, thatta way it’s nigh impossible to exfiltrate the private key.
I never would have been able to figure this out without the extensive help from the Yubico official documentation and especially this post from james(bl)og. I’ll be relaxing the security requirements by a bit in my guide as it fits my (assumed) threat model better. Let’s get cracking!
Guide
First off, we’re going to need to create the CA on the Yubikey. That’s going to require generating a keypair and self-signing it so the public key can be exported.
Generate the keypair and sign
ykman piv keys generate --touch-policy ALWAYS 9c ca-key.pem
This instructs the Yubikey to generate the public/private keypair, using a touch policy of always. I’m using this touch policy as I’m using the default PIV/PUK pins. If they didn’t have to be at least 6 digits, I’d change them, but I’m not too concerned about local attacks.
ykman piv certificates generate -s "SSH CA" -d 3650 9c ca-key.pem
This generates a certificate, signed with the private key on the Yubikey, valid for ~10 years. I still haven’t quite been able to grok why this is necessary other than the Yubikey requires it… PKI is complicated.
Extract the CA’s public key
ssh-keygen -D ~/.nix-profile/lib/libykcs11.dylib
This should print all the public keys on your Yubikey to the terminal. The one we want is labeled ‘Public key for Digital Signature’. Copy from the ssh-rsa to that phrase into a new file called ca.pub. That’s the CA’s public key! You will very likely have the library for this located someplace else. You can find this in the Yubico documentation. Unless you’re weird, like me, and you use nix on MacOS. More about that another day ;).
Sign some keys!
ssh-keygen -s ${PATH_TO}/ca.pub -D ${LIBRARY_PATH}/libykcs11.[dylib|so] -I <identifier> ${HOME}/.ssh/id_ed25519.pub
If you’re using the default pin, it’s 123456
. And with that you’ve now got a shiny new signed SSH key! But how to use it? Look at james(bl)og under “Setting up servers” for that answer! Or check out SSHD_CONFIG(5).
I’m not going to give all the answers, I’m writing this post more so I can remember how I did it than to share the method ;)
In summary
ssh-keygen -D ~/.nix-profile/lib/libykcs11.dylib # Extract the CA's public key
ssh-keygen -t ed25519 # Generate a new key
ssh-keygen -s ca.pub -D ~/.nix-profile/lib/libykcs11.dylib -I <email> ~/.ssh/id_ed25519.pub # Sign the shiny new key
Assuming that the CA is already set up on the Yubikey, it’s plugged in, and yubico-piv-tool
is installed, it’s just 3 commands and you’re ready to log in to any server where your CA’s public key has been installed!
Thanks for reading! <3