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
ここまでお読みいただきありがとうございました!