I’m using SSH on a daily basis. It’s how I authenticate with varios code forges like GitHub or Codeberg. Furthermore, I’m using it to sign my Git commits. This let’s others verify easily that I’m the author of a commit. Everybody should sign their commits.
What is SSH cryptographically?
SSH manages a public / private key pair. You can give your public key to services, servers, people and SSH proves to these entities that the person with the private key, you, made a certain request / statement / signature.
How SSH keys are usually stored
I don’t have any real data about this, but I’m almost sure that 95% of all developers store their SSH keys in plain files
in their .ssh folder. And no, most people don’t set a password that they need to type every time they use a key.
That’s what the defaults in ssh-keygen and friends push you to do. I used to do it like this too. But that’s problematic.
We’re seeing an unprecedented wave of supply chain attacks. Modern software stacks like JS, Python or Rust rely heavily on 3rd party packages. Supply chain attacks are a logical consequence. The initial assumption that our computers only run trusted software doesn’t hold anymore, in my opinion.
This means that we need to restrict access to our private SSH keys. I see two practical solutions:
Password managers
Use a password manager. Some of them can act as ssh-agent, rendering usage rather pleasant.
The password manager encrypts the SSH key on disk, making it inaccessible to malware. They prompt the user
for confirmation / a finger print / etc. on access. They also make it easy to synchronise SSH keys.
I’m using a password manager for my SSH keys at work and I can recommend it. However, for my private life I have another solution that I like even more.
Hardware keys
Regular readers of the blog know what I’m talking about: FIDO hardware security tokens.
openssh supports generating and storing keys directly on FIDO hardware tokens. The secret key stays on the device and can’t be leaked by design.
The ssh utils ask for user confirmation (by touching the hardware token) when a key is used. This solves the unauthorized malware problem.
The keys can be “resident”, which means that they’ll be stored on the FIDO token. This solves the synchronisation problem. You can download them onto any computer with
ssh-keygen -K
This will ask you for your PIN and then generate the public key.pub and secret key files. The secret file is a stub and still needs the FIDO key to
authenticate. The secret never leaves your key. You can optionally protect the key file with a password and
you can require the PIN for every interaction. I’m doing neither to keep the setup convenient.
Generating a key is simple:
ssh-keygen -t ed25519-sk -O resident -O application=ssh:SOME_KEY_NAME -C "your@mail.org" -N '' -f ~/.ssh/SOME_KEY_NAME
This will generate a key with SOME_KEY_NAME. It won’t be password protected and it won’t ask for your PIN on every use.
You can of course choose a more secure path. Yubico has a good tutorial on the matter.
Which one should I choose?
As always, it depends. If you already have FIDO keys, I’d say that’s the logical way to handle SSH. The secret stays on the key no matter what. Security by design at its best. And it’s convenient.
Password managers are a bit easier to use, but less secure. They are also less portable, which can be a real disadvantage. We’re already using one at work, so this seemed like the path of least resistance. I can’t complain, it works well in practice.
The most important thing is that you shouldn’t choose neither and stay with passwordless key files. They are unsafe and should be avoided. The alternatives are ready. Are you?