見出し画像

RDSにローカルから接続する踏み台EC2をTerraformで作成する #490

大まかな手順

以下の手順で実行できます。

  1. 踏み台サーバーを起動する

  2. SSMでポートフォワーディングを実行する

  3. ローカルからmysqlコマンドでRDSに接続する

前提

ローカルでaws cliを実行できる状態にしておく必要があります。当然認証も突破していないといけません。今回はこの部分は割愛します。

また、RDSはMySQLを使っている想定です。

それでは各手順を見ていきます。

踏み台サーバーを起動する

踏み台サーバーの設定(EC2)

EC2サーバーを定義します。ちょっとした工夫として、amiはハードコードせずに動的に取得しています。

resource "aws_instance" "bastion" {
  ami                         = data.aws_ssm_parameter.amazon_linux_2_arm.value
  instance_type               = var.ec2_instance_type
  subnet_id                   = var.subnet_id
  associate_public_ip_address = false
  iam_instance_profile        = aws_iam_instance_profile.ssm_profile.name
  vpc_security_group_ids      = [aws_security_group.bastion.id]

  user_data = file("${path.module}/user_data.sh")

  tags = {
    Name = "${var.project}-bastion"
  }
}

# fetch newest amazon linux2 instance profile
data "aws_ssm_parameter" "amazon_linux_2_arm" {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2"
}

user_dataには以下のシェルファイルを設定します。サーバー起動時に、RDSへの接続に必要なソフトをインストールして使える状態にしています。

#!/bin/bash
set -eux

echo "STARTING SETUP..."

yum update -y

sudo yum install -y mysql

# update ssm-agent
sudo yum install -y https://s3.ap-northeast-1.amazonaws.com/amazon-ssm-ap-northeast-1/latest/linux_arm64/amazon-ssm-agent.rpm
sudo systemctl restart amazon-ssm-agent

echo "FINISH SETUP"

IAMロールの設定

SSMを実行するためのロールを付与します。

resource "aws_iam_role" "bastion_ssm" {
  name = "BastionHostSSMRole"
  assume_role_policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [{
      "Action" : "sts:AssumeRole"
      "Effect" : "Allow",
      "Principal" : {
        Service : "ec2.amazonaws.com"
      }
    }]
  })
}

resource "aws_iam_role_policy_attachment" "ssm_attach" {
  role       = aws_iam_role.bastion_ssm.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_iam_instance_profile" "ssm_profile" {
  name = "BastionHostSSMProfile"
  role = aws_iam_role.bastion_ssm.name
}

セキュリティグループの設定(踏み台サーバー側)

以下は1例です。最低限の権限を付与します。

# 踏み台サーバーが外部や他リソースにアクセスする際の制限を定義する
resource "aws_security_group" "bastion" {
  name   = "${var.project}-bastion"
  vpc_id = var.vpc_id

  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # SSMエージェントがインターネットと通信するため
  }

  # RDSインスタンスに対してポートフォワーディングを行うため、BastionホストがRDSのポート3306に直接通信できるようにする
  egress {
    from_port       = 3306
    to_port         = 3306
    protocol        = "tcp"
    security_groups = [var.db_security_group_id] # このセキュリティグループに属するリソースへのアクセスが許可される

  }

  tags = {
    Name = "${var.project}-bastion"
  }
}

セキュリティグループの設定(RDS側)

踏み台サーバー用の設定のみを書き出します。MySQL

# 踏み台サーバーがRDSに接続することを許可するためのルール
resource "aws_security_group_rule" "db_from_bastionr" {
  type                     = "ingress"
  from_port                = 3306
  to_port                  = 3306
  protocol                 = "tcp"
  security_group_id        = var.db_security_group_id
  source_security_group_id = aws_security_group.bastion.id # このセキュリティグループに属するリソースからのアクセスが許可される
}

これで準備が整いました。

SSMでポートフォワーディングを実行する

肝となるコマンド部分だけ記載します。シェルファイルで諸々の情報を動的に取得するようにしています(詳細は次の記事でまとめます)。

ssm_port_forward() {
  HOST=$1
  PORT=$2
  INSTANCE_ID=$3

  aws ssm start-session \
    --target ${INSTANCE_ID} \
    --document-name AWS-StartPortForwardingSessionToRemoteHost \
    --parameters '{"host":["'"${HOST}"'"],"portNumber":["3306"], "localPortNumber":["'"${PORT}"'"]}' \
    --profile ${PROFILE}
}

aws ssm start-sessionの、AWS-StartPortForwardingSessionToRemoteHostという機能を使ってポートフォワーディングしています。

parametersのHOSTにはRDSのエンドポイントを、PORTにはローカルのポート番号(任意)を指定します。

profileはaws cliの認証に使っているものを指定します。

コマンドが無事に実行されれば、DBがConnection待ちの状態になるはずです。

ローカルからmysqlコマンドでRDSに接続する

ローカルのポートにRDSをポートフォワーディングしているので、いつも通りmysqlにアクセスコマンドを叩けばOKです。hostにはlocalhostを、portには先ほどのポート番号を指定します。

mysql --user=your_user_name --password='your_password' --host=127.0.0.1 --port=ポートフォワーディング時に指定したポート番号

DataGripなどを使用している場合でも、上記の内容で設定すればもちろん使えます。


ここまでお読みいただきありがとうございました!

参考


いいなと思ったら応援しよう!