This tutorial will be a short and sweet introduction into setting up ssh bastion hosts.

What is a SSH bastion:

SSH bastions (jump hosts) are used to middleman SSH connections between isolated networks. In a high security scenario, say a backend database server, we want complete isolation from the internet. However, we may require remote access to machines, so we have a middle man which is connected to both interfaces.

Bastions are commonly used in cloud environments to securely access VMs which lack public IP addresses, but it can be used for any type of server.

"Dumb" vs "Smart" - Middlebox vs Bastions

In the past, to improve my security on my SSH servers, I used iptables to restrict ssh access only to my static home IP.

If I wanted to access these servers outside of home, I'd first ssh home,
then once I have a shell at home, I'd ssh into the webserver.

The connection to my webserver thus originates from home. It's simple in concept but it's clunky and amateurish

So having a 'master server' that we ssh into, and from there, launch a new ssh process to connect into our infrastructure sounds reasonable right? In fact, how is this configuration any different from a bastion host.

Well, there's two massive problems

The identity is contained on the workstation, there is no authentication between the client and the endpoint.

  1. What we have is completely manual, no good for scripts etc. We need to launch a shell to the middle box everytime

We need a better solution than "Hey, Lets store the keys to everything in a single place. Better yet, why not open that place up to the internet!"

The smart way (how bastions work)

Recall that with SSH you can forward ports between the client and the ssh server (the ssh server works as a proxy).

With a proxy based solution, we don't put anything sensitive on the bastion server. The id_rsa key remains on the client, and only on the client.

Basically the bastion is just acting as a gateway and isn't really participating in the ssh connection between you (the external client) and your internal server.

All the magic is done with a single client instance of ssh.

Let's set it up

$ vi ~/.ssh/config

Host bastion
  Hostname 192.0.2.66
  Port 22
  User bastion-user
  IdentityFile ~/.ssh/bastion_host_x509.pem


Host *.etherarp.net
  ProxyCommand ssh bastion -W %h:%p

Now any connections on etherarp.net will pivot through the bastion. You can set up a ACL/firewall on the clients to only allow connections from the bastion IP.

Primary Use Case

You have cloud instances that are on a private only network. You want authenticated access from outside. You create a bastion that has both a public facing IP and access to the internal network.

Authenticated connections from the outside, pivot through the bastion in order to reach the internal end points.

In my upcoming post we'll look at best practices of setting up dedicated bastions on Amazon EC2 and further extensions to secure SSH such as SSHFP dns records.

It's not just for cloud

The principles of bastions can be applied to other set-ups too. Perhaps, you have a NAT set up at home. Rather than port forwarding, you could use the SSH service on your router as a bastion. Although, the principle of bastions is that they don't run other services.

You can also use them for random collections of SSH internet hosts you have. Simply set a firewall rule that SSH traffic is only allowed inbound from the bastion.

Then for extra security, you can optionally add outbound rules on the bastion, limiting its egress ssh access only to your allowed preset of hosts.