<aside> ⚠️
By default, RDS requires all traffic to the instances to have SSL enabled. Make sure the DB connection from your apps has SSL required
</aside>
<aside> 📝
Resources needed for the bastion host:
IAM Role & Instance Profile
Security group
Key pairs
EC2 instance </aside>
Create an IAM role for the SSM instance, with the following policies:
AmazonSSMManagedInstanceCore/* modules/**bastion**/main.tf */
# IAM Role, Policies, and the Instance Profile
resource "aws_iam_role" "bastion_rds_role" {
name = "${var.project_name}-bastion-rds-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "ec2.amazonaws.com"
}
},
]
})
}
resource "aws_iam_role_policy_attachment" "ssm_policy_bastion_rds" {
role = aws_iam_role.bastion_rds_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_instance_profile" "bastion_rds_profile" {
name = "${var.project_name}-bastion-rds-profile"
role = aws_iam_role.bastion_rds_role.name
}
Create a security group for the bastion host:
# Security Group
resource "aws_security_group" "bastion_rds_sg" {
name = "${var.project_name}-bastion-rds-sg"
description = "SG of bastion host for RDS instances"
vpc_id = var.vpc_id
tags = {
Name = "${var.project_name}-bastion-rds-sg"
}
}
resource "aws_vpc_security_group_egress_rule" "bastion_rds_allow_https" {
security_group_id = aws_security_group.bastion_rds_sg.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "tcp"
from_port = 443
to_port = 443
}
resource "aws_vpc_security_group_egress_rule" "bastion_rds_allow_postgresql" {
security_group_id = aws_security_group.bastion_rds_sg.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "tcp"
from_port = 5432
to_port = 5432
}
Create a key pair from our local machine’s console, then reference the public key:
# Replace "~" with "$HOME" on Windows, as PowerShell does set the "$HOME" variable automatically (or use any directory you desire)
ssh-keygen -t rsa -f ~/.ssh/eks-demo-bastion-rds
# Key pair
resource "aws_key_pair" "bastion_rds" {
key_name = "${var.project_name}-bastion-rds"
public_key = file(pathexpand("~/.ssh/eks-demo-bastion-rds.pub"))
}
Create the EC2 access instance:
data "aws_ami" , reference from the same file /modules/bastion/main.tf# EC2 Instance
resource "aws_instance" "bastion_rds" {
ami = data.aws_ami.al2023-arm64.id
instance_type = "t4g.nano"
key_name = aws_key_pair.bastion_rds.key_name
subnet_id = var.subnet_ids.bastion
vpc_security_group_ids = [aws_security_group.bastion_rds_sg.id]
iam_instance_profile = aws_iam_instance_profile.bastion_rds_profile.name
root_block_device {
volume_size = 10
volume_type = "gp3"
encrypted = true
delete_on_termination = true
}
tags = {
Name = "${var.project_name}-bastion-rds"
}
}
We can output the bastion’s instance ID for port forwarding later:
/* modules/**ecr**/**outputs.tf** */
****
output "bastion_rds_instance_id" {
value = aws_instance.bastion_rds.id
}
/* outputs.tf (root) */
output "bastion_rds_instance_id" {
value = module.bastion.bastion_rds_instance_id
}
terraform validate && terraform fmt
terraform plan -out tf.plan
terraform apply "tf.plan"

<aside> 📝
Resources needed for the RDS DB instances:
RDS subnet group
Security group
RDS instances </aside>
Setup the rds module; with vpc module’s outputs (VPC ID, subnet IDs), eks module’s EKS cluster computed security group ID, bastion module’s RDS bastion security group ID:
/* modules/**eks**/outputs.tf */
****
output "eks_cluster_sg_id" {
value = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
}
/* modules/**bastion**/outputs.tf */
****
output "bastion_rds_sg_id" {
value = aws_security_group.bastion_rds_sg.id
}
### CREATE A NEW MODULE: **rds** ###
/* modules/**rds**/variables.tf */
# Referencing from root
variable "project_name" {
type = string
}
variable "vpc_id" {
type = string
}
variable "subnet_ids" {
type = map(string)
validation {
condition = (
contains(keys(var.subnet_ids), "rds1") &&
contains(keys(var.subnet_ids), "rds2")
)
error_message = "The subnet_ids must contain 'rds1', 'rds2'"
}
}
variable "eks_cluster_sg_id" {
type = string
}
variable "bastion_rds_sg_id" {
type = string
}
/* main.tf */
module "rds" {
source = "./modules/rds"
project_name = local.project_name
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.subnet_ids
eks_cluster_sg_id = module.eks.eks_cluster_sg_id
bastion_rds_sg_id = module.bastion.bastion_rds_sg_id
}