This article connects to MySQL database provisioned in RDS using a jumphost or bastion host ec2 instance. In scenarios where direct access to the RDS instance is restricted to private networks, employing a Jump Host server hosted in a public subnet becomes essential. This technical article serves as a comprehensive guide for establishing a secure connection to an RDS database through a Jump Host server.
The following diagram shows the configuration when this tutorial completes.
Network Infrastructure Setup:
VPC Creation: Start by creating a VPC named "jump-vpc" with cidr block 25.0.0.0/16.
Subnet Creations: For this scenario, we will create one public subnet with cidr block 25.0.25.0/24. Second is private subnet for seating RDS database which requires to subnet created in two availablity groups.
Route table: Create a route table and association for public subnet assigning to a internet gateway which will enable this subnet to access internet. Similarly, for private subnet, assign route to a NAT gateway which will indirectly enable internet access to the private network.
Here is the terraform code for VPC, subnet, route table creation.
resource "aws_vpc" "jumpbox" {
cidr_block = var.vpc-cidr
tags = {
Name = var.vpc
}
}
# Create one subnet for jumpbox server
# create two private subnets for DB server
resource "aws_subnet" "jumpbox" {
vpc_id = aws_vpc.jumpbox.id
cidr_block = var.jumpbox-cidr
availability_zone = "us-east-1a"
map_public_ip_on_launch = true
tags = {
Name = var.jumpbox-subnet
}
}
# These two subnets are for RDS
resource "aws_subnet" "rds" {
count = length(var.availability_zones)
vpc_id = aws_vpc.jumpbox.id
cidr_block = "25.0.${count.index + 1}.0/24"
availability_zone = var.availability_zones[count.index]
tags = {
Name = "Private-Subnet-RDS"
}
}
resource "aws_db_subnet_group" "rds" {
name = "rds-subnet-group"
subnet_ids = aws_subnet.rds[*].id
tags = {
Name = "rds-subnet-group"
}
}
Security Group: security group is like firewall rules controlling access bothwise (ingress, egress) . This is defined at the VPC level, the mapping of SG happens at the resource level while create RDS, EC2 or any instance.
For Jumpbox instance, we allow ingress port 22, 80 and egress full access to internet.
For RDS instance, we allow ingress port 3306 (SQL listener port) from specific subnet (in this case above public subnet).
Below TF code, beautifully shows public & private subnet.
# This security group is for jumpbox resource "aws_security_group" "jumpbox" { name = var.sg-jumpbox vpc_id = aws_vpc.jumpbox.id description = "Allow all inbound traffic" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "allow http 8080 port" from_port = 8080 to_port = 8080 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } egress { from_port = 0 to_port = 0 protocol = -1 cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } tags = { Name = var.sg-jumpbox } } # Security group for RDS to be created resource "aws_security_group" "rds" { name = var.sg-rds vpc_id = aws_vpc.jumpbox.id egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 3306 to_port = 3306 protocol = "tcp" cidr_blocks = [aws_subnet.jumpbox.cidr_block] } }
Jumpbox EC2 Instance Setup: Now that we got VPC, IG, Subnet, route-table, security group created, we will create a jumpbox server residing in public vpc. Below terraform code shows the configuration.
resource "aws_instance" "jumpbox" { ami = var.ami instance_type = var.instance_type key_name = var.key_name user_data = file(var.startup_script) tags = { Name = "jumpbox" } vpc_security_group_ids = ["${aws_security_group.jumpbox.id}"] subnet_id = aws_subnet.jumpbox.id associate_public_ip_address = true }
Above script, uses, vpc, subnet & security groups as defined above. User_data attribute is used to execute shell script as startup. key_name attribute enhance access security using public/private keys.
Create RDS instance using Terraform script. Below Terraform code, helps to create a RDS server with MySQL. Here is the configuration.
resource "aws_db_instance" "rds" {
identifier = "rds-mysql-instance"
allocated_storage = 20
engine = "mysql"
engine_version = "5.7.41"
instance_class = "db.t3.micro"
db_name = "myDB"
username = "admin"
password = "mypassword"
vpc_security_group_ids = [aws_security_group.rds.id]
db_subnet_group_name = aws_db_subnet_group.rds.id
multi_az = false
skip_final_snapshot = true
}
In the above code snippet, db_subnet_group_name is a group of subnets in atleast in two availability zones. Refer to subnet snippet for mapping aws_db_subnet_grup with private subnet that we have configured. multi_az can be false if we donot want database created in two zones. Remaining attributes are straight forward, terraform script simplifies RDS DB creation to a large extent.
Connecting to RDS through Jumbox: After implementing above configuration.
ssh to jumpbox
# install MySQL client on Ubuntu
$ apt-get install mysql-client
# connect to RDS using Mysql client
$ mysql -h <refer_to_rds_host name> -P 3306 -u admin -p
password:
mysql:> show databases;
mysql:> use myDB; # refer to tf code db_name creation.
Conclusion: Establishing a secure connection to an RDS database through a Jump Host server hosted in a public subnet is a fundamental practice for maintaining data integrity and confidentiality in cloud environments. By following the guidelines outlined in this technical article, organizations can ensure robust security measures while enabling seamless access to their RDS instances.