DEV Community

Nathan (Nursultan) Bekenov for AWS Community Builders

Posted on • Edited on

Securely connect to an Amazon RDS

Hello there! In this post I am going to show you Terraform code example of how to create resources for secure connection to your DB in RDS cluster.


I am going to follow approach provided by AWS team in this article

Ok, let's figure out what resources we need to create.
I assume that you already have: VPC and RDS Cluster (if not yet then check out previous post ).

  • VPC endpoints (ssm, ssmmessages, ec2messages)
  • EC2 instance
  • Security Group for EC2 instance
  • IAM role and instance profile

I will put details after each part of the code. Also if you want to skip and jump right to the code then everything can be found in my repo

Below code creates VPC endpoints. Since we need 3 of them I am looping through the list. We also will need security group.

# ---------------- # VPC Endpoints # ---------------- locals { endpoints = { "endpoint-ssm" = { name = "ssm" private_dns = false }, "endpoint-ssm-messages" = { name = "ssmmessages" private_dns = false }, "endpoint-ec2-messages" = { name = "ec2messages" private_dns = false }, } } resource "aws_vpc_endpoint" "endpoints" { for_each = local.endpoints vpc_id = module.vpc.vpc_id vpc_endpoint_type = "Interface" service_name = "com.amazonaws.${data.aws_region.current.name}.${each.value.name}" security_group_ids = [aws_security_group.vpc_endpoint_sg.id] subnet_ids = data.aws_subnets.private.ids private_dns_enabled = each.value.private_dns } # SG for VPC endpoints resource "aws_security_group" "vpc_endpoint_sg" { name_prefix = "vpc-endpoint-sg" vpc_id = module.vpc.vpc_id description = "security group for VPC endpoints" ingress { from_port = 0 to_port = 65535 protocol = "tcp" cidr_blocks = [module.vpc.vpc_cidr_block] description = "allow all TCP within VPC CIDR" } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] description = "allow all outbound traffic from VPC" } tags = { Name = "vpc-endpoints-sg" } } 
Enter fullscreen mode Exit fullscreen mode

Now let's create EC2 instance and configure instance profile for it.

resource "aws_instance" "bastion_host" { ami = data.aws_ami.amazon_linux_2_ssm.id instance_type = "t3.nano" subnet_id = data.aws_subnets.private.ids[1] vpc_security_group_ids = data.aws_security_groups.vpc_endpoint_sg.ids iam_instance_profile = aws_iam_instance_profile.bastion_host_instance_profile.name user_data = templatefile("ssm-agent-installer.sh", {}) disable_api_termination = false metadata_options { http_endpoint = "enabled" http_tokens = "required" } tags = { Name = "ssm-bastion-host" } } ## Instance profile resource "aws_iam_role" "bastion_host_role" { name = "EC2-SSM-Session-Manager-Role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } Action = "sts:AssumeRole" } ] }) } resource "aws_iam_role_policy_attachment" "bastion_host_role_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" role = aws_iam_role.bastion_host_role.name } resource "aws_iam_instance_profile" "bastion_host_instance_profile" { name = "EC2_SSM_InstanceProfile" role = aws_iam_role.bastion_host_role.name } 
Enter fullscreen mode Exit fullscreen mode

For Instance IAM role we are using existing policy AmazonSSMManagedInstanceCore that we will need in order to be able to use SSM.
Note that in user_data I am using shell script to install necessary packages.

#!/bin/bash main(){ #####Installing dependencies and packages #### echo "Installing Security Updates..." sudo yum -y update echo "Installing ec2 instance connect..." sudo yum install ec2-instance-connect echo "Installing latest aws-ssm agent..." sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm sudo systemctl enable amazon-ssm-agent echo "Starting latest aws-ssm agent..." sudo systemctl start amazon-ssm-agent sudo amazon-linux-extras enable postgresql14 sudo yum -y install postgresql } time main > /tmp/time-output.txt 
Enter fullscreen mode Exit fullscreen mode

Once all infra is created follow the steps from my Readme
https://github.com/nbekenov/rds-aurora/blob/main/bastion_host/README.md

  • Create a remote port forwarding session
aws ssm start-session \    --region us-east-1 \    --target <bastion instance id> \     --document-name AWS-StartPortForwardingSessionToRemoteHost \     --parameters host="<rds endpoint name>",portNumber="5432" localPortNumber="5432" 
Enter fullscreen mode Exit fullscreen mode
  • Connect to DB using PGAdmin

Image description

Use username and password from AWS Secrets Manager


In the next post I will be providing details on how to run DB Migrations using Flyway and Lambda Function

Top comments (0)