You probably already know how to create and register an ssh key pair.
Simple enough.
You can then copy the pub key into [insert relevant UI here] or just send it to your sever with ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
.
However, when using more than one service or handling more than one server, it might be best to use different keys.
Why use multiple ssh keys
On one hand, it limits the impact of a compromised key.
If a machine gets compromised, but the ssh keys it used only granted access to a limited set of services, one can rest assured that the other services are probably fine.
This is especially relevant when separating work from personal keys.
It’s also useful for revocation. You can cut access to one key/machine without affecting others.
Or set the ssh key for an untrustworthy machine to expire on a short cycle.
Fine, you create multiple ssh keys, and now find yourself having to run your ssh commands like ssh -i ~/.ssh/key user@server
or even worse, having to ssh-add ~/.ssh/key
before managing your remote git repo.
This kinda sucks, but there is a better solution.
Config file
You might not be aware that ssh will look for a client config under ~/.ssh/config
.
The file follows this basic structure:
You can have as many of these as you want.
The file is read up-to-down and the first match is used, so the least specific sections should be at the bottom.
This config for example, would use the first section for that IP, while using the wildcard at the end for all other ssh connections:
Handling multiple services and keys
In practice, you might end up with a config that looks like this:
Note here that, since a HostName
is provided, the Host
in the last section acts as the alias one would use to refer to that service.
So for that section, you would run ssh vps
instead of ssh vps_usr@209.85.231.104
, much less verbose.
Since the first two sections will be used by git
, adding a HostName
and a User
doesn’t make much sense.
For starters, git
will always default to the git
user, no need to explicitly set that.
Plus when working on GitHub/GitLab hosted repos, one would clone something like git@github.com:ORG/REPO.git
, so the Host
would always be the same as the HostName
, thus making it redundant.
Of course, other options can be set in the config file, like Port
or ConnectTimeout
.
But there are more clever things that can be done.
Advanced options
There are, of course, many more options than these.
These are just used to show the usefulness of an ssh config file.
Proxy Jump
Depending on the security requirements of an organization, a ProxyJump
might be needed when connecting to a server.
This simply means that the outgoing connection must go through a dedicated server before being redirected to final one, which might for example not be exposed to the internet.
To do this, one would ssh -J jump_host target_host
.
As you might imagine, each might have different settings, so that command is bound to get messy.
You could create a shell alias, or you could use the ssh config:
This allows the ssh command to look like ssh target_host
, no need to worry about who jumps where and with which credentials.
Port Forwarding
Another security-related config is ssh tunneling or port forwarding.
This is done with something like:
Which means ‘please take all traffic going to localhost:3000
and send it to example.com
on port 3306
’
The second localhost
is from the perspective of the remote server.
This might seem a bit silly. Why not just point directly to example.com:3306
?
The interesting bit here is that the traffic is being sent through the ssh connection (so port 22
by default).
The server would receive the traffic on :22
and re-route it to :3306
.
This might be interesting not only to reduce the number of exposed ports in a server, but also to ensure cryptographic security. There’s no need to use SSL/TLS here, OpenSSH is plenty secure and comes for free with no work needed on either side of the communication.
Of course, one could route more than one ports, and point to more than the remote “localhost
”, with a designated user, etc.:
This is not exactly easy to type, but a config like this might help:
One would only need to run ssh what_a_mess
.
As you might tell, LocalForward
implies there is also a RemoteForward
, which indeed is used to send traffic the other way around (from the server to the client).
Just be careful when committing this config to your dotfiles repo: make sure no sensitive information is public!