背景
AWSでは、データベースをセキュアに管理するために、RDSインスタンスをプライベートサブネットに配置することが一般的。しかし、プライベートサブネットに配置されたRDSインスタンスにアクセスするためには、通常、踏み台(Bastion)ホストが必要で、これらの方法は、セキュリティ上のリスクも伴う。
そこで、AWS Systems Manager (SSM) セッションマネージャーを利用することで、これらのリスクを解消し、セキュアにRDSインスタンスにアクセスしようと思う。
やることのイメージ
LocalHost
┆
(SSM)
↓
SSM EC2 Instance (Public Subnet)
┆
(SSM)
↓
RDS Instance (Private Subnet)
※SSM EC2 Instance も、Private Subnetにおくほうがいいらしい? が、SSHで中身確認したりしたいので、Publicにおいてる
Terraform で SSM EC2 Instance 構築
VPC、Subnet、RDS Instance などの作成は割愛
IAM Role 作成
resource "aws_iam_role" "ssm_role" {
name = "ssm-role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
Service = "ec2.amazonaws.com"
},
Action = "sts:AssumeRole"
}
]
})
inline_policy {
name = "ssm-policy"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = [
"ssm:DescribeInstanceInformation",
"ssm:SendCommand",
"ssm:ListCommandInvocations",
"ssm:ListCommands",
"ssm:ListDocuments",
"ssm:ListInventoryEntries",
"ssm:ListTagsForResource",
"ssm:PutInventory",
"ssm:UpdateInstanceInformation",
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel",
"ec2messages:AcknowledgeMessage",
"ec2messages:DeleteMessage",
"ec2messages:FailMessage",
"ec2messages:GetEndpoint",
"ec2messages:GetMessages",
"ec2messages:SendReply"
],
Resource = "*"
}
]
})
}
}
EC2 にアタッチする IAM Instance Profile 作成
resource "aws_iam_instance_profile" "ssm_instance_profile" {
name = "ssm-instance-profile"
role = aws_iam_role.ssm_role.name
}
SSM EC2 Instance 作成
resource "aws_instance" "ssm_instance" {
ami = "ami-04b4ba2f09ee72e61" # ※参考
instance_type = "t2.micro"
subnet_id = aws_subnet.style_assistant_public_subnet_a.id
iam_instance_profile = aws_iam_instance_profile.ssm_instance_profile.name
vpc_security_group_ids = [aws_security_group.ssm_instance_sg.id] # ※※参考
tags = {
Name = "style-assistant-ssm-instance"
}
}
※ ami は、以下コマンドで取得。最新を使えばいいはず!
aws ec2 describe-images --region ap-northeast-1 --filters "Name=name,Values=amzn2-ami-hvm-*-x86_64-gp2" --query "Images[*].[ImageId,CreationDate]" --output text | sort -k2 -r | head -n1
※※ security_groups を使うと、terraform apply
で 毎回インスタンスを新規作成するので、vpc_security_group_ids を利用
Security Group 作成
resource "aws_security_group" "ssm_instance_sg" {
name = "ssm_instance_sg"
description = "Allow SSM access"
vpc_id = aws_vpc.style_assistant_vpc.id
egress {
# from_port = 0 と to_port = 0 の組み合わせは特別な意味を持ち、実際にはすべてのポート番号を許可することを意味
from_port = 0
to_port = 0
protocol = "-1" # TCP、UDP、ICMPなど、すべてのプロトコルの通信を許可
cidr_blocks = ["0.0.0.0/0"] # 全世界のすべてのIPアドレスに対して通信を許可
}
}
動作確認
SSM接続
aws ssm start-session \
--target i-XXX \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["style-assistant-db.XXX.ap-northeast-1.rds.amazonaws.com"],"portNumber":["3306"], "localPortNumber":["3307"]}'
MySQL接続
mysql -h 127.0.0.1 -P 3307 -u XXX -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 588
Server version: 8.0.35 Source distribution
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
まとめ
このアーキテクチャにより、SSHキーやパブリックIPアドレスを使用せずに、セキュアにプライベートサブネット内のRDSインスタンスにアクセスすることができる。SSMセッションマネージャーを使用することで、セキュリティリスクを低減し、管理が容易になる。