Terraformで構築するPrivate SubnetのRDSインスタンスへのアクセス手順

## 背景
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セッションマネージャーを使用することで、セキュリティリスクを低減し、管理が容易になる。