At this point, it should basically be “Stupid SSH tricks™”, but whatever.
Prerequisites: Basic understanding of *nix and SSH
Scenario
You have a server behind a firewalled network and you need to connect. You could just do something like ssh first-server
and from there ssh internal-server
. Not too bad, right?
What if there’s a whole subnet of servers that you might wanna reach? What if you don’t wanna SSH twice? What if you’re using something that wants to execute from your local machine but can’t really handle the manual two step SSH jump (such as Ansible)
This is where SSH Multiplexing comes in very handy
Solution, part 1: Pivot box
As you probably expected by now, we’re going to be digging into our ssh config file, so go ahead and pop an editor open to ~/.ssh/config
The first thing we want to do is setup our “gateway” or “bastion” or “jump” host. Whatever you want to call it. Doesn’t matter to me. Here’s an excerpt of mine with a breakdown of each line in the config
host jump
User fraq
Hostname foo.bar.baz
ControlMaster auto
ControlPath ~/.ssh/proxy-%r@%h:%p
ControlPersist 5m
host jump
defines a friendly name in SSH for your machine. Note that this isn’t in /etc/hosts
, so you can’t ping jump
, but you can ssh jump
. When you do use ssh jump
, ssh opens up the config file, looks for a host entry that matches, and then uses that config to build the connection. Nothing we haven’t covered already in previous chapters.
User fraq
is the username we use to connect to jump
Hostname foo.bar.baz
means that we connect to a server called foo.bar.baz
in DNS. This can also be an IP address.
These next three are the ones you need for multiplexing:
ControlMaster auto
tells the ssh connection that you want to listen for control connections (used for multiplexing)
ControlPath
tells ssh where to put the control socket for the connections and how to format the file names. Per the OpenSSH cookbook:
The combination %r, %h and %p stand for the remote user name, the remote host and the remote host’s port. The control sockets should be given unique names.
ControlPersist
tells ssh how long to leave the master open.
Solution, part 2: Target box
Now that your jump host is setup to accept multiplexed SSH connections, it’s time to tell the SSH how to connect to your target box through the jump box.
Host target
ProxyCommand ssh -W %h:%p jump
User fraq
Hostname 10.10.10.10
As you can see, it looks very similar to a standard config file, except for the ProxyCommand
option. This tells the ssh connection to execute that command first as a prerequisite for connecting to the target machine. In our case, we’re saying that we want to ssh -W
through the machine known to ssh as jump
.
Conclusion
With this in place, you can now use jump
as a pivot to get into internal networks that it can access but you cannot, all without having to ssh
twice manually. This means scripts or tools that invoke ssh
can be used locally on your machine as well.
And yes, this can be chained basically indefinitely, so you can create some pretty long and crazy proxy connections.
Also, I very intentionally skipped over the in-depth explanation of ssh -W
and the older ssh nc
implementation. The whole purpose of this post was just to setup ssh multiplexing.