RDS Proxy with HAProxy

It is good practice to isolate your valuable data from the evil internet. The absolute basis is to have a subnet without a route to either a NAT gateway or Internet Gateway. A misconfiguration eg an open Security Group will not lead to exposure of your data due to being an ‘un-routeable’ subnet. The local route still applies to this subnet, so other subnets can still communicate with this subnet.

Let’s call this subnet the database subnet, and you should launch your RDS or DocumentDB or valuable instances in this subnet.

However, at some point during a migration data has to be migrated from the old database to the new one. This is where the fun starts. There are multiple options to do this like:

  • Using the beloved DMS service (pain to setup)
  • Setup a bastion host with SSH tunneling (needs SSH keys)
  • Using a VPN connection (needs VPN client and setup)

All of these options have their pros and cons. But they all have one thing in common: You need some sort access into the AWS account.

It is not usually to get the request from clients to get direct access to the data for validation purposes during the migration/golive phase.

A solution to allow business users and non-technical user access to the database with their own tools and without explaining VPN and SSH, is to use a proxy on a bastion host.

You should try to get an SSH tunneling setup working before, but if that is not possible, this is a “good” alternative.

Disclaimer

This should be a temporal solution! Make sure the bastion host security group is as tight as possible eg. no use of 0.0.0.0/0 for the db port

HaProxy

HAProxy is a free, very fast and reliable reverse-proxy offering high availability, load balancing, and proxying for TCP and HTTP-based applications

Sounds perfect for this use case. The gist is that we will run HaProxy on a bastion host to give us access to the database in the database subnet.

Please make sure the RDS user account does not have a common name and password. So no admin/admin :)

Let’s get started:

  1. Setup a bastion host in the public subnet and make sure it gets a public IP address. (SSM access is recommended). Use the Amazon Linux 2 AMI.
  2. Add user data to install Haproxy:
#!/bin/bash
sudo dnf install -y haproxy
cat << EOC | sudo tee -a /etc/haproxy/haproxy.cfg
listen db_cluster
   bind *:3030 # Custom port to access the cluster, Choose something that does't immidiatly scream 'database' 
## MariaDB balance leastconn - the cluster listening on port 3030.
   mode tcp
   balance source
   option tcpka
   server db <REPLACE WITH RDS ENDPOINT WITH PORTNUMBER>
EOC
sudo systemctl enable haproxy
sudo systemctl start haproxy
  1. Update the Security group of the bastion host to allow access to the custom port (3030 in this example). Source IP should be the IP of the client that needs access to the database.
  2. Update the RDS Security Group to allow access from the bastion.
  3. Launch the instance, login with SSM to validate the configuration and that HaProxy is running.
  4. Connect to the bastion host and test the connection to the database with any db client on the public ip of the bastion host on the HaProxy port (3030 in this example).

Use with care, don’t open up whole CIDRs, shutdown when not needed!

Keep this in mind to minimize the risk of a breach.