At the very best Agent Forwarding is a feature that I want to make sure no one ever uses again… why?
It’s dangerous - you’re placing a socket that will happily answer cryptographic challenges that it shouldn’t be in the hands of unknown parties.
It’s only marginally easier than the alternative.
So what is it?
Well as usual the man page is fairly helpful here:
1 2 3 4 5 6 7 8 9 |
|
The normal reason why you would want to forward your agent is because you’re connecting to some server via some other server (usually because a direct connection isn’t available).
The diagram below shows a fairly standard scenario where a DB server can’t be accessed via the public internet, but can be indirectly accessed via the web server:
What a lot of people do at this point is forward their key with something like:
1 2 3 |
|
Which is relatively simple (and can be simplified more so by turning on authentication agent forwarding in ssh_config), but it’s terrible unless you completely trust the security of your web server (please don’t do that).
Lets look at why it’s so terrible:
- Anyone else with sufficient access to the web server can use your forwarded agent to authenticate to anything you have access to.
- Most web servers have known vulnerabilities that you probably haven’t patched for yet.
- 1 + 2 = terrible
To be clear I’m not saying that we’re forwarding actual bits of key material to an untrustworthy host, just that we’re forwarding a connection to an agent that is able to answer authentication challenges to another host you may have access to. In practice one way attackers might use this is if they can see the environment variables your SSH connection came in via (either they have gained access to your account or root) then they could interrogate the SSH_AUTH_SOCK environment variable, add that in to their own environment and use your authentication agent to initiate authenticated connections to other hosts while you are still connected to the untrustworthy host.
So what’s the alternative?
ProxyCommand + nc.
ProxyCommand is a (seemingly little known) directive you can give to SSH to say “hey before you connect to where I’ve told you to, fire up a socket to something arbitrary first”. “nc” (or netcat) is something to give you an arbitrary connection.
Here’s an example (continuing on from above):
1 2 |
|
What this does is connects to webserver, authenticates using your key as you and then runs “nc” replacing in the hostname and port for the dbserver as it does. This will return a socket (running over the encrypted SSH connection) that can connect directly to the dbserver. SSH will then connect to the socket as you and authenticate with your key, but note that the encryption between you and the dbserver is end-to-end so you don’t need to make your authentication agent available in any potentially untrustworthy environments.
Ok that’s great and all but it’s too much to type
Put it in your ~/.ssh/config file, for the example above something like this should work:
1 2 |
|
Once that’s in place you can just run:
1 2 |
|
What about a range of hosts?
The only real thing to watch out for here is that if you match a range of hosts and the host you’re routing via is in that matched range, SSH will quite happily fork bomb your machine:
1 2 3 4 5 |
|
What if I have to jump via multiple hosts?
Well firstly, redesign your network.
If for some reason that’s not a realistic option, you can just stack hops together:
1 2 3 4 5 6 7 |
|
But it’s so slow…
In some circumstances doing this can be slower (e.g. when you spend all your time connected to an intermediate server connecting to other servers). This is because you’re now firing up multiple SSH connections each time you make a new connection instead of just one.
One pretty common work around for this is:
1 2 3 |
|
Run “man ssh_config” and search for “ControlMaster” to read up in more detail about this.
The TL;DR of it is - ControlMaster creates multiplexing magic to convert multiple connections down to one (meaning much less build-up / tear-down lag).
Similarity to onion routing
Using ssh like this is very similar to onion routing in that you have end-to-end encryption (and authentication!) by only trusting each mid-point to run up a socket (courtesy of netcat) for you. However please don’t assume that because the encryption going on here is similar to TOR that you can use it to alleviate the privacy concerns that TOR does.
Update: clarified that the agent and not the key is being forwarded, also explained a little more depth what that means.