Ssh – How to use port tunneling to connect to a private database instance through a network bastion

amazon-web-servicessshssh-tunnel

I have a network bastion which is publicly accessible at example.compute-1.amazonaws.com and a private postgres database instance at postgres.example.us-east-1.rds.amazonaws.com:5432

I can ssh into the bastion using

$ ssh -i key.pem ec2-user@example.compute-1.amazonaws.com

Then once I'm in the bastion I create a ssh tunnel with:

$ ssh -i key.pem -L 5432:postgres.example.us-east-1.rds.amazonaws.com:5432 ec2-user@example.compute-1.amazonaws.com

I can then verify that the tunnel works by connecting to the database from the bastion using localhost:

$ psql -p 5432 -h localhost -U postgres

However, I am unable to connect to the database remotely (without being in the bastion).

$ psql -p 5432 -h example.compute-1.amazonaws.com -U postgres
psql: could not connect to server: Connection refused
Is the server running on host "example.compute-1.amazonaws.com" () and accepting
TCP/IP connections on port 5432?

I've configured the security group of the bastion to accept inbound traffic on port 5432.

Am I using ssh -L correctly? Should I be using it outside the bastion? Any advice would be much appreciated.

Best Answer

When you create an SSH tunnel, it does not expose the opened port to the outside world. The opened port, is only available as localhost. So effectively what you've done is to create a tunnel from your bastion, to your bastion.

Instead, what you want to do is create a tunnel from your local computer through your bastion.

So, you create your tunnel as part of your connection from your local computer to your bastion. You do not need to create another SSH connection.

So, locally, you would execute:

$ ssh -i key.pem -L 5432:postgres.example.us-east-1.rds.amazonaws.com:5432 ec2-user@example.compute-1.amazonaws.com

Assuming postgres.example.us-east-1.rds.amazonaws.com resolves to the private IP address.

Then to connect to your server, still locally, connect as if the server was local:

$ psql -p 5432 -h localhost -U postgres

Doing this, there's no need to use a prompt on your bastion.