I recently had a need to further secure an RDS server so that it was no longer publicly facing but would instead be accessed via SSH. It is easy to mess something like that up if you need to setup all the parts manually but thankfully AWS have a quick start that does the majority of the heavy lifting. Once the deployment was finished I could move the RDS so that it lived on the private subnet but even when I was connected to the bastion server I couldn't connect to the RDS server.

What the quick start doesn't give any guidance on is what to do next once you have this all setup so what was missing? This is probably immediately obvious to anyone who lives and breaths AWS everyday but what was missing was than I needed to update the security group for the private subnet to allow Inbound traffic from the public subnet where the bastion server resides. Being picky I limited the access to just the ports I needed.

Once I could connect to the RDS server from the bastion server (I used netcat to test this), I then updated the Inbound rules of the security group so that only specific IP ranges could connect to the bastion server using SSH. To test the SSH tunnel I needed to enable SSH tunneling by setting AllowTcpForwarding yes in the /etc/ssh/sshd_config, followed by sudo systemctl restart sshd.service to allow the new settings to take effect.

Adding more users

Now that the RDS server was secured I needed to allow others access to the same RDS server via the SSH tunnel but I also wanted to restrict them to SSH tunneling, i.e. no interactive sessions on the bastion server. To achieve this I created a linux user that could be restricted to SSH tunneling only and would be used by the other users of the RDS

First, create a new linux user and switch to it

sudo adduser -m bastion
sudo passwd bastion
su - bastion

Then, create a .ssh folder and add an authorized keys file to host the public keys of each user

mkdir .ssh
chmod 700 .ssh
cd .ssh
touch authorized_keys
chmod 600 authorized_keys
nano authorized_keys

Then add each public key (e.g. .ssh\id_rsa.pub) of each user that needs access. Finally as we don't want the "bastion" user to have an interactive session over SSH we add the following entry to the bottom of /etc/ssh/sshd_config and restart the sshd service again.

Match User bastion
  ForceCommand echo 'This account can only be used for tunnelling'

With this in place, only users with the correct private keys and on the expected networks can connect to the RDS server via the SSH tunnel.

I am sure there are other ways to achieve this.

[Update 18/11/2020] I would also recommend reading up on best practices for securing your bastion server as these change as we learn more about the threats we face.

As always your feedback is important.