SSH tunneling to access AWS RDS using Bastion Host and IAM role

Marcin Cuber
3 min readOct 19, 2020

General

SSH tunneling is a method of transporting arbitrary networking data over an encrypted SSH connection. It can be used to add encryption to legacy applications. It can also be used to implement VPNs (Virtual Private Networks) and access intranet services across firewalls.

SSH is a standard for secure remote logins and file transfers over untrusted networks. It also provides a way to secure the data traffic of any given application using port forwarding, basically tunneling any TCP/IP port over SSH. This means that the application data traffic is directed to flow inside an encrypted SSH connection so that it cannot be eavesdropped or intercepted while it is in transit. SSH tunneling enables adding network security to legacy applications that do not natively support encryption.

In our case, we have a RDS Aurora MySQL cluster in private subnet which can only be accessed via bastion host. We are going to take advantage of IAM role as we enabled IAM DB authentication on the RDS DB instances.

Bastion Host Port: 22 and RDS Aurora MySQL Port: 3306

Database endpoint: database-name.cluster-cdho8ligqqad.eu-central-1.rds.amazonaws.com

Opening SSH tunnel cli

ssh -N -L 3307:database-name.cluster-cdho8ligqqad.eu-central-1.rds.amazonaws.com:3306 -p 22 ec2-user@30.143.243.20

This will forward port 3307 from your local desktop to the remote Aurora MySQL RDS cluster through a Public facing bastion EC2 instance, in our case it is bastion with IP 30.143.243.20.

The key here is -L which says we’re doing local port forwarding. Then it says we’re forwarding our local port 3306 to database-name.cluster-cdho8ligqqad.eu-central-1.rds.amazonaws.com:3306, which is the default port for MySQL DB.

Flag -N indicates to not execute a remote command. This is useful for just forwarding ports.

For more SSH info, you can simply run ssh man in your terminal.

Setting for .ssh/config

Host rds_tunnel
User ec2-user
Hostname 30.143.243.20
Localforward 3307 database-name.cluster-cdho8ligqqad.eu-central-1.rds.amazonaws.com:3306
IdentityFile ~/.ssh/id_rsa.pem

and then you can simply use

ssh rds_tunnel

Access DB without IAM

The above command will open a SSH tunnel and now you can access your database by running:

mysql -u username -h 127.0.0.1 -P 3307 -p password

Access DB with IAM role

The difference when working with IAM roles is the fact that you need to generate Auth Token. You need to generate an AWS authentication token to identify the IAM role and this is effectively your password. Remember that you need to have your AWS credentials set as normal in order to generate necessary credentials for your RDS.

Note: generated token expires within 15 minutes of creation.

#!/usr/bin/env bashREGION="eu-central-1"
IAMDBUSER="user-iam-admin"
HOSTNAME="database-name.cluster-cdho8ligqqad.eu-central-1.rds.amazonaws.com"
# Make sure you have the right region for the token!!
TOKEN="$(aws rds generate-db-auth-token --hostname ${HOSTNAME} --port 3306 --username ${IAMDBUSER} --region=${REGION})"
mysql -h 127.0.0.1 -P 3307 --enable-cleartext-plugin --user=${IAMDBUSER} --password=${TOKEN}

In the script above, you can easily follow three variables being set, that is REGION, IAMDBUSER and HOSTNAME. They are all required to generate the auth token.

Creating IAM DB User

Something, I have not discussed as part of this article is how to create IAM DB users. To create a database user account that uses an AWS authentication token you need to connect to your RDS with master credentials as an example. Now we are going to create user-iam-admin db user:

CREATE USER user-iam-admin IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';

(Optional) Run this command to require the user to connect to the database using SSL:

GRANT USAGE ON *.* TO 'user-iam-admin'@'%'REQUIRE SSL;

Conclusion

Solution above is what I am using on daily basis. I have tried using SQLPro for MySQL application, however I couldn’t make it work with IAM roles. This is mainly because of the additional flag that you need to use which is — enable-cleartext-plugin.

I hope this article will help people progress quicker :).

More stories available at marcincuber.medium.com

--

--

Marcin Cuber

Technical Lead/Principal Devops Engineer and AWS Community Builder