This is the third part of a series about using SSH with bastion hosts. You may wish to read the other parts if you haven’t already:
- Part 1: Using SSH Through A Bastion Host Transparently
- Part 2: Using SSH Bastion Hosts With AWS and Dynamically Locating Them With EC2 Tags
SSH Connection Multiplexing
If you might be opening multiple connections through the bastion host, either to a single machine or to multiple machines, it’s possible to use “connection multiplexing” to share the same connection to the bastion host as a transport to many ssh connections. This saves both resources and time establishing new connections. For a more in-depth discussion of connection multiplexing, look here.
In brief, to enable basic connection multiplexing, add the
ControlPersist keys to your
~/.ssh/config file, as shown (the first two lines are the same as before):
Host destination.com ProxyCommand ssh -A email@example.com -W %h:%p ControlPath ~/.ssh/controlmasters/%r@%h:%p ControlMaster auto ControlPersist 10m
A note of warning about ControlPersist: That tells SSH to leave a connection open from the client machine to the bastion host. This may not be desirable or considered safe, depending on your environment. You may omit it and still benefit from multiple concurrent connections (such as when using GIT or Ansible) sharing resources.
If you chose to use
ControlPersist, you can close the connection manually with the command
# Close the connection nicely -- waiting for connections to close: ssh -O stop destination.com # Close the connection forcefully, terminating all active connections: ssh -O exit destination.com
BONUS #2: Port Forwarding and SOCKS Proxy
Credit to my colleague Timothy Weiand for suggesting this be added.
It is possible to have the ssh connection act as a SOCKS proxy. (See the section under “DynamicForward” at the
ssh_config man page.) This can be useful to use as a light-weight temporary VPN. There are many security considerations to be taken into account, since you will be potentially creating a tunnel from your local network (which might be a coffee shop!) to the network on the other side of the bastion host, so use with caution, and don’t leave this open longer than necessary!
You may add
-D port to the ssh command line, or
DynamicForward port to the config file to tell ssh to listen for SOCKS4 or SOCKS5 connections on port on the local host. It will stay open as long as the connection is active, which is often as long as the shell into the other machine is open. (Combine this with connection multiplexing and ControlPersist for longer-term SOCK proxy connections. Use with caution!)
Note that you can add this to the connection to the bastion host or to the connection to the destination machine, depending on where you want the proxied connections to be coming from. To have the SOCKS proxy terminate at a machine on the other side of the bastion host, simply add the
-D port to the ssh connection to that machine, like so:
ssh -D 1234 firstname.lastname@example.org destination.com#
Now you can configure any software that supports SOCKS proxies (such as a web browser) to use
localhost:1234 as the SOCKS proxy and, as long as that connection is open, those proxied connections will appear to be coming from the destination machine to other devices on the same network, including the destination machine.
In order to make the connections appear to be coming from the bastion host, you can either ssh directly to the bastion host, or add the
-D port to the ssh command to the bastion host in the configuration file (bold portions are the relevant addition):
Host destination.com ProxyCommand ssh -A -D 1234 email@example.com -W %h:%p
Now, if you open a connection normally (without the -D on the command line) to the destination machine, it will also open a SOCKS proxy terminating at the bastion host that lasts as long as the connection to the bastion host. (The connection multiplexing and
ControlPersist setting can make that last longer than the connection to the destination machine, however.)
You can also forward arbitrary local ports (without a SOCKS proxy) to arbitrary host/port combinations through the SSH tunnel in a similar manner. Replace the
-D port in the above examples for SOCKS with
-L port:host:host_port to forward port on localhost to connect to
host on port
host_port. It will appear to come from either the bastion host or the destination machine, the same as for SOCKS connections.
Note that you cannot open ports <=1024 to listen to unless you are root on most OSes, so you’ll need to pick an unused port higher than 1024 most of the time.
You can also forward ports of the other side of the ssh connection to come through the tunnel and come from your local machine to your local network, including the localhost. Just replace
-L port:host:host_port with
-R remote_port:host:host_port, and it will forward any connections to
remote_port on the machine you’re connected to to host:host_port as if they came from your localhost. The same rules about opening listening ports <=1024 apply to remote_port — you will most likely have to be root, and many ssh configurations will not allow you to ssh directly in as root.
Credit to my colleague Timothy Weiand for helping research this.