Secure Access to MySQL Port via SSH Tunnel
What Is an SSH Tunnel?
In modern cloud environments, exposing databases directly to the internet is a serious security risk. For this reason, database servers are typically placed inside private subnets. However, this makes external access harder.
This is where SSH Tunnel (Port Forwarding) comes in. It lets us open a secure “tunnel” through a bastion host to reach resources in a private subnet. In other words, we establish an encrypted connection — via the bastion host — to a database without a public IP.
✅ Advantages
- Provides access without assigning a public IP.
- Encrypts traffic for better security.
- Minimizes the attack surface.
In this lab, we will set up an SSH Tunnel from a bastion host to an RDS MySQL database and connect using both a GUI tool (like DBeaver) and the terminal.
🎯 Goal
- Provide secure access to a MySQL instance in a Private Subnet via a bastion host.
- Connect to the database without exposing it to the public network.
🛠 Steps
Architecture Components
- Bastion EC2 (Public Subnet, SG: 22/tcp)
- Database-1 (RDS MySQL) (Private Subnet, SG: 3306/tcp → allowed only from Bastion SG)
[Client PC]
│
│ SSH Tunnel (Port 22)
▼
[Bastion Host - Public Subnet]
│
│ Internal Network (Port 3306)
▼
[RDS MySQL - Private Subnet]Creating the Bastion Host
EC2 → Instances → Launch an instance
- Name: Bastion Host
- Instance type: t2.micro
Key Pair
- Create a new key pair:
ec2_ssh_key - Type: RSA
- Format:
.pem
- Download the file to your computer.
Save the key file to your computer.
Network settings → Edit
- VPC: default
- Subnet: default
- Availability Zone: default
- Auto-assign public IP: Enable
- Firewall (SG): Create a new security group
- Security group name:
Basiton_SG - Description: Security group for
Basiton_SG - Rules:
- SSH → Source: Anywhere (0.0.0.0/0)
Click Launch instances; your bastion server will be ready in a few minutes.
Test connection to the bastion:
ssh -i ec2_ssh_key.pem ec2-user@<BastionPublicIP>chmod 400 ec2_ssh_key.pem
ssh -i ec2_ssh_key.pem ec2-user@54.88.146.50Creating the MySQL Server (RDS)
Aurora and RDS → Create a database
- Choose a database creation method: Standard create
- Engine options: MySQL
- Editions: MySQL Community
- Templates: Dev/Test
- Availability and durability: Single-AZ DB instance deployment (1 instance)
Settings
- DB instance identifier:
database-1 - Credentials Settings
- Master username:
admin - Credentials management: Self managed
- Password: Set your own password.
Instance configuration
- DB instance class → Burstable classes (includes t classes)
- Instance type:
db.t3.micro
Storage
- Storage type: default
- Allocated storage: 20
Connectivity → Connect to an EC2 compute resource
- EC2 instance: Bastion host
- Network type: IPv4
- Virtual private cloud (VPC): default
- DB subnet group: Automatic setup
- Public access: No
- VPC security group (firewall): Create new
- New VPC security group name:
Mysql
Accept all other default settings and click Create database.
👉 Wait until Database Status becomes Available.
In the AWS Console, click database-1 to prepare for connection to the database:
👉 Note the RDS endpoint address.
Connecting to MySQL via SSH Tunnel
You can connect to MySQL over an SSH tunnel using tools like DBeaver (https://dbeaver.io/download/) or MySQL Workbench (https://dev.mysql.com/downloads/workbench/).
🔹 With DBeaver
- Connection Settings → SSH
- Host/IP: Bastion Public IP
- User Name:
ec2-user - Authentication method: Public key
- Add bastion host SSH key:
ec2_ssh_key.pem - Click Test tunnel connection to verify.
The SSH tunnel from the Bastion Host to RDS MySQL has been established successfully.
Now let’s configure the RDS MySQL connection:
- Connection Settings → Main
- Server Host: RDS Endpoint
- Username:
admin - Password: your password
- Click Test Connection to connect to RDS MySQL.
Connection successful.
We created a database named Hakan.
🔹 From the Terminal
SSH Tunnel (local port forward):
Create an SSH tunnel from your local machine:
ssh -i ec2_ssh_key.pem -L 3306:<PrivateDBIP>:3306 ec2-user@<BastionPublicIP>ssh -i ec2_ssh_key.pem -L \
3306:database-1.c4t40ua0c47v.us-east-1.rds.amazonaws.com:3306 \
ec2-user@54.88.146.50Connect to MySQL:
mysql -h 127.0.0.1 -P 3306 -u admin -p🧹 Cleanup
To avoid ongoing costs after completing the lab:
- Bastion Host → Terminate
- RDS MySQL → Delete
