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"
}
}
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
}
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
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 \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters host="",portNumber="5432" localPortNumber="5432"
- Connect to DB using PGAdmin
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cg6u777u8d7z3hlpx47r.png)
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