見出し画像

RDSのポートフォワーディングをシェルスクリプトでいい感じに実行する #491

こちらの中で割愛した、ポートフォワーディングを実行する部分のシェルスクリプトについてです。

ポートフォワーディングとは

単純に表現すると「あるポートにきたデータを別のところに転送する」という意味です。ここでは、ローカルのポートに来たリクエストをRDSのポートに転送して、ローカルのPCからRDSに対するCRUDを実行できるようにすることを意図しています。

ポートフォワーディングには踏み台サーバーのインスタンスIDが必要ですが、EC2をTerraformで作成していると、何かの変更時にdelete - createでインスタンスIDが変わってしまうことがよくあります。

インスタンスIDをハードコードしていると、その都度スクリプトも書き換えないといけなくて大変です。

そのためインスタンスIDを動的に取得して実行する手順を考えてみます。

インスタンスIDを動的に取得する

以下のスクリプトで可能です。describe-instancesでJSON形式でインスタンスの情報が取れるので、予め設定したNameでフィルターして踏み台サーバーの情報に絞ります。

get_bastion_instance_id() {
 echo $(aws ec2 describe-instances \
   --profile ${PROFILE} \
   --filters "Name=instance-state-name,Values=running" "Name=tag:Name,Values=my-sample-bastion" | \
   jq -r '[(.Reservations[].Instances[].Tags[] | select(.Key == "Name").Value),.Reservations[].Instances[].InstanceId][1]')
}

RDSエンドポイントを動的に取得する

ついでにポートフォワーディング対象のRDSエンドポイントも動的に取得するようにしてみます。こちらはSSMのパラメータストアにエンドポイントを文字列として保存しておいて、そこから取得するようにしています。

get_rds_writer_endpoint() {
 echo $(aws ssm get-parameter \
  --profile ${PROFILE} \
  --name /my-sample/rds/mysql/endpoint \
  --query 'Parameter.Value' | tr -d '"')
}

endpointは「〜rds.amazonaws.com」で終わる部分までで、ここではポート番号までは不要です。

ポートフォワーディングする

上記を組み合わせて、動的なポートフォワーディングができます。
例として、ローカルのポート9990を使うように設定しています。

#!bin/bash

PROFILE=$1


get_bastion_instance_id() {
 echo $(aws ec2 describe-instances \
   --profile ${PROFILE} \
   --filters "Name=instance-state-name,Values=running" "Name=tag:Name,Values=my-sample-bastion" | \
   jq -r '[(.Reservations[].Instances[].Tags[] | select(.Key == "Name").Value),.Reservations[].Instances[].InstanceId][1]')
}

get_rds_writer_endpoint() {
 echo $(aws ssm get-parameter \
  --profile ${PROFILE} \
  --name /my-sample/rds/mysql/endpoint \
  --query 'Parameter.Value' | tr -d '"')
}

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}
}


connect_db() {
  INSTANCE_ID=$(get_bastion_instance_id)
  if [ -z ${INSTANCE_ID} ]; then
    echo "ERROR: aws bastion instance id NOT FOUND!" 1>&2
    exit 1
  fi

  MYSQL_WRITER_ENDPOINT=$(get_rds_writer_endpoint)
  if [ -z ${MYSQL_WRITER_ENDPOINT} ]; then
    echo "ERROR: aurora endpoint url NOT FOUND!" 1>&2
    exit 1
  fi

  ssm_port_forward ${MYSQL_WRITER_ENDPOINT} 9990 ${INSTANCE_ID}

}


connect_db

以下のように実行すればOKです。
※シェルファイル名を「connect_db.sh」とする

sh connect_db.sh your_profile_name


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

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