It’s not always possible to ssh to a host directly. Many networks require high-value systems to be accessed via an intermediate bastion/proxy host that receives extra attention in terms of security controls and log monitoring. The added security provided by this connection bouncing comes with a cost in convenience, though. It requires multiple logins to access the protected systems and substantially complicates scp/stfp file transfers.
Fortunately, there are a number of ways to automate connection bouncing and make it as convenient as direct connection. There are already a number of web-sites detailing the approaches to this issue, and I won’t repeat their contents, to get a broad overview of the topic read the following:
- SSH Bouncing Part 1 from Hacking Linux Exposed
- SSH Bouncing Part 2 from Hacking Linux Exposed
- Using rsync through a firewall, the concepts in this document apply to all SSH setups, not just those integrating rsync
SSH Connection “Chaining”
Connection “chaining” refers to any approach that involves sshing to an intermediate host, and then sshing from the intermediate host to the next host (for example: ssh 1 'ssh 2 "ssh 3"'). This solution is attractive for setups with many hops because it’s easy to extend, for example sshto makes this very easy. The primary disadvantage is that end-to-end encryption is lost. The connection is decrypted by every host in the chain, and an attacker with sufficient privilege on an intermediate system can sniff the connection without compromising either of the endpoints. I consider this to be a significant failing, and have a strong preference for “stacked” connections wherever they are logistically feasible.
SSH Connection “Stacking”
Connection “stacking” refers to any solution that involves tunneling ssh connections inside each other. “Nesting” strikes me as a better term, but stacking seems to be more widely agreed upon. It is typically implemented with proxy-commands or with ssh port-forwarding. It can be more difficult to manage for connections with many hops, and it forces one of the endpoints to bear the encryption load of all the connections (in chained setups, the load is spread evenly among all the hosts in the chain). It does maintain end-to-end encryption, preventing connection/credential sniffing by intermediate hosts.
The key properties for my setup are:
- End-to-end encryption is maintained using stacked connections
- For putty, multiple hops are supported via saved sessions. For WinSCP, only a single hop is supported.
- Putty is used for shell connections, and WinSCP is used for scp/sftp connections
- No special software is required beyond a default Putty installation, WinSCP, and an SSH server with port forwarding enabled. Specifically, netcat is not required on the intermediate host as is common with ProxyCommand setups.
The WinSCP Config is quite simple and utilizes its “tunnel” feature. Open WinSCP and configure a saved session for the final destination host as follows:
- On the Session page, fill in the hostname and user name for the final destination host. Leave the password blank.
- Check the “Advanced options” box in the login dialog.
- Select the Connection –> Tunnel page.
- Check the “Connect through SSH tunnel” box.
- Fill in the Host name and user name of the intermediate host. Leave the password blank.
- Save the session using the button in the lower right-hand corner of the window.
When you log in using the new profile, you will be prompted for two passwords. The first is for your account on the intermediate host, and the second is for your account on the final-destination host. After login, the bounce is entirely transparent and WinSCP works as if you had connected directly to the final-destination host. The connection process can be made even more transparent and secure by using public key authentication with Pageant instead of passwords.
The Putty setup is slightly more complicated and requires that public key authentication be used on the intermediate host. It utilizes Putty’s “local proxy” feature, which allows you to specify an arbitrary command on the local machine to act as a proxy. Instead of creating a TCP connection, PuTTY will communicate using the proxy program’s standard input and output streams. Our local proxy will be plink, which is a command-line ssh connection program included in the Putty default installation. Plink’s -nc option provides functionality similar to the ProxyCommand/netcat approach, but does so using the ssh server’s native port-forwarding interface and does not require that netcat be installed on the intermediate system. To set things up, configure a saved session for the final destination host:
- Configure public key authentication for the intermediate host and make sure it works.
- Start putty and on the “Session” page of the “Putty Configuration Dialog” that appears, fill in the host name and user name for the final destination host.
- Switch to the Connection –> Proxy page, select “Local” as the proxy type enter the following as the local proxy command: plink.exe intermediate.proxy.host -l username -agent -nc %host:%port
- Save the session.
Remember to replace “intermediate.proxy.host” with your intermediate hostname and “username” with your real username. “%host” and “%port” are variables that putty will feed to plink at connection time, so leave those as is. If all is working properly, when you log in using the new profile plink will handle the login to the intermediate system silently. Putty isn’t smart enough to prompt if the proxy command requires user input, so you’ll get a connection error if public key authentication on the intermediate host isn’t working. If you use password authentication on the final destination host you’ll be prompted for your password, or if you use pubkey authentication there as well you’ll land at a prompt with no fuss at all.
If you have trouble, make sure plink is executing properly. You may need to enter the full pathname, usually c:\program files\putty\plink.exe. You can also try executing the plink command from a prompt, remembering to substitute the %host and %port values of your final destination host. If it’s working properly, you’ll be logged into the intermediate system with your pageant-cached private key, and instead of a prompt you’ll be presented with the SSH banner for your final destination system.
Before attempting multiple hops, get a single-hop setup up and running. Additional hops simply extend the same concepts using saved sessions. By way of example, assume that you have 2 hops on the way to a server: PuttyClient -> IntermediateServer01 -> IntermediateServer02 -> FinalServer
- Create a saved session for IntermediateServer01 with no proxy config, since it’s directly accessible from your PuttyClient workstation.
- Create a saved session for IntermediateServer02 with a local proxy command of ‘plink -load server01 -nc %host:%port’.
- Create a saved session for FinalServer with a local proxy command of ‘plink -load server02 -nc %host:%port’. When you attempt to SSH to FinalServer with this saved profile, plink will try to setup the proxy using the profile for server02 which has a local proxy command that calls back to the server01 config. This technique can be extended to any number of hops, thanks to Tim for pointing it out in the comments.