privacy-focused ssh keys management
This is the opinionated way I manage my ssh keys.
If you use SSH or Git but aren’t familiar with SSH keys,
I strongly recommend you to learn about them. It’s one of those small time investments that
will make your work significantly easier in the long run.
This quick recap is probably all you need to know to get started and follow along:
- Ssh keys are a safer alternative to passwords for authenticating to ssh.
- What we colloquially call an ssh key is actually a key pair. There is a private key that must remain in your computer, and a public key that can be shared, and its comparable to a padlock that only the private key can open.
- git supports ssh to connect to remote repositories. This makes ssh keys the recommended (and easiest) way to authenticate to github or other remote git servers.
Oh and in case you are wondering what they physically look like, both the private and public key are just a long sequence of letters in a text file.
Generating a key
This command will generate a brand new key pair:
ssh-keygen -t ed25519 -f ~/.ssh/test_key -C "key description"
-
-t ed25519
Sets the algorithm. In 2024 ed25519 is the preferred choice; It’s widely supported, and it produces keys that are much shorter than rsa 4096, while remaining as safe. -
-C "key description"
Sets the key description. It will be part of the public key, and is therefore something that you share. A good description should help you - and whoever you share the key with - to understand where the private key is stored, and who is the owner. Something likeAlberto Ventafridda work_thinkpad
-
-f ~/.ssh/test_key
Sets the path where the key pair will be saved, and the filename. The sensible default is to save all keys in the.ssh
folder in your home directory.
I like to generate a dedicated ssh key for every service that requires it.
With this practice your ssh folder will grow pretty quickly, which is why
it’s important to give a descriptive name to the key file, for example github_work
.
You might be wondering what’s the point of having dedicated ssh keys, when it’s absolutely safe to use the same key for multiple services. Allow me to explain:
The case for using dedicated ssh keys
When ssh tries to authenticate via public key, it sends the server all your public keys, one by one, until the server accepts one.
This is a minor information disclosure issue, since public keys can then be used by a potential attacker to link someone’s presence to private infrastructure, or github accounts.
You can see this in action by running running ssh with the -v
flag, or by connecting to
ssh whoami.filippo.io
To avoid this disclosure I like to generate a dedicated ssh key for every service that requires it,
and explicitly associated the key to the host in the .ssh/config
file.
You can see an example here:
#~/.ssh/config
#some ssh server
Host homelab.halb.com
User admin
IdentitiesOnly yes
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_homelab
# By default, don't send any ssh public key to avoid
# information disclosure to potential attackers.
# This block must be at the END of the config file
Host *
PubkeyAuthentication no
IdentitiesOnly yes
IdentityFile ~/nonexistent
User ubuntu # A popular username
This practice will also solve another potential issue:
When your client tries to authenticate with all possible keys in your .ssh
folder, and there are too many of them, you will exceed the remote server
MaxAuthTries
limit and get the error Too many Authentication Failures
.
Since we are not sending any key at all, except for the ones we explicitly bind
to a host, our client will never encounter this error.
The case for avoiding ssh keys on the cloud
I want to mention very briefly this topic because I’ve seen a lot of ssh keys misuse in this area: If you are manually setting ssh keys to access cloud infrastructure, chances are there are better ways to manage authentication that better integrate with the existing IAM layer.
For example, Google cloud offers Os login which binds a Google identity to linux user accounts on a VM. Compared to basic access, this system will allow you to:
- provide fine grained authorization using Google IAM
- integrate two-step verification
- integrate audit logging
- you won’t need to keep inventory of existing ssh keys
AWS offers similar features with EC2 Instance connect, and I’m sure other clouds have similar systems.
All these cloud providers offer an authentication / access control layer on top of all their services, which becomes completely useless the moment you bypass it with your own hardcoded SSH keys.
Of course this discussion applies only to cloud infrastructure; ssh keys remain a convenient tool in all other situations.
Using ssh alias
You can create host aliases for static Ips or hostnames that are too long to type. For example:
#~/.ssh/config
Host vps
HostName a.very.long.hostname.com
IdentitiesOnly yes
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_vps
In this example, to connect to the server you can simply type ssh vps
managing multiple github accounts
The practice of manually associating keys to hosts makes it very easy to authenticate to multiple github accounts. You just have to create a host alias.
For example, I created a host alias for my work github account called github.com.work
.
Every time I need to clone a github repository from my work account, i simply run
git clone git@github.com.work:organization/repository.git
and my ssh client will automatically
use the correct key. This is the ssh config:
#~/.ssh/config
#personal github.com
Host github.com
IdentitiesOnly yes
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_personal_github
#work github.com (example usage: git clone git@github.com.work:your-repo.git)
Host github.com.work
HostName github.com
IdentitiesOnly yes
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_work_github
putting everything together
This is an example of ssh config that integrates everything I’ve mentioned so far:
#~/.ssh/config
#some ssh server
Host homelab.local
User admin
IdentitiesOnly yes
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_homelab
#personal github.com
Host github.com
IdentitiesOnly yes
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_personal_github
#work github.com (example usage: git clone git@github.com.work:your-repo.git)
Host github.com.work
HostName github.com
IdentitiesOnly yes
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_work_github
# By default, connect to a ssh server with user ubuntu - a very common username,
# and don't send any ssh public key to avoid information disclosure to potential attackers.
# This block must be at the END of the config file
Host *
PubkeyAuthentication no
IdentitiesOnly yes
IdentityFile ~/nonexistent
User ubuntu