「DB接続に挑戦」の1つ目の記事です。
はじめに
検証環境でシナリオ試験を行うための環境構築の際、
「こちらのシェルでポートフォワードして繋いでください」
と指示があり、test_file.shファイルを渡されました。
「ポートフォワードって何?」
「このファイルは何をするもの?」
と分からないことが多かったので、調べたことを記載します。
目次
ポートフォワードとは
ポートフォワード(ポートフォワーディング)とは、
インターネットから特定のポート番号宛てに届いたパケットを、あらかじめ設定しておいたLAN側の機器に転送する機能です。
ポートフォワーディングを用いることでインターネットに接続するグローバルIPアドレスをひとつに絞り、効率的にセキュリティ対策などが行え、社内LANにつながる複数のローカルコンピュータが直接、外部と通信する心配がありません。
ポートフォワーディングは、SSLといった暗号化技術を併用するケースがほとんどで、通信全体が暗号化されます。
引用:ポートフォワーディングとは | クラウド・データセンター用語集/IDCフロンティア
シェルファイル
渡されたファイルがこちらです。
一部は適当な値に書き換えています。
export AWS_ACCESS_KEY_ID="自分のアカウントのアクセスキー"
export AWS_SECRET_ACCESS_KEY="自分のアカウントのシークレットアクセスキー"
#######
# 設定
#######
CLUSTER="dev-test-ecs-cluster-bff"
REGION="ap-northeast-1"
DB_HOST="test-host"
DB_PORT="5432"
PORTFORWARD_PORT="56432"
TASK_VALUE=`aws ecs list-tasks --cluster ${CLUSTER} --region ${REGION}`
TASK_ARN=`echo "${TASK_VALUE}" | jq '.taskArns[0]' | jq -r .`
RUNTIMEID_VALUE=`aws ecs describe-tasks \
--cluster ${CLUSTER} \
--task ${TASK_ARN} \
--region ${REGION}`
JSON_LEN=`echo "${RUNTIMEID_VALUE}" | jq '.tasks[0].containers' | jq length`
for i in `seq 0 $((${JSON_LEN} - 1))`; do
ROW=`echo "${RUNTIMEID_VALUE}" | jq ".tasks[0].containers[${i}]" | jq -r .`
IMAGE=`echo ${ROW} | jq -r .image`
if [ ${IMAGE} != 'null' ]; then
RUNTIMEID=`echo ${ROW} | jq -r .runtimeId`
fi
done
TASKID=(${RUNTIMEID//-/ })
START_SESSION_TARGET="ecs:${CLUSTER}_${TASKID}_${RUNTIMEID}"
aws ssm start-session \
--target ${START_SESSION_TARGET} \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters "{\"host\":[\"${DB_HOST}\"],\"portNumber\":[\"${DB_PORT}\"], \"localPortNumber\":[\"${PORTFORWARD_PORT}\"]}" \
--region ${REGION}
解説
1. AWS認証情報を指定
export AWS_ACCESS_KEY_ID="自分のアカウントのアクセスキー"
export AWS_SECRET_ACCESS_KEY="自分のアカウントのシークレットアクセスキー"
2. 接続先の設定
CLUSTER="dev-test-ecs-cluster-bff"
REGION="ap-northeast-1"
DB_HOST="test-host"
DB_PORT="5432"
PORTFORWARD_PORT="56432"
- CLUSTER:どのECSクラスターの中のタスクへ接続するか
- DB_HOST:AWS内部からのDBホスト名
- DB_PORT:DBのポート(Postgres → 5432)
- PORTFORWARD_PORT:ローカルPCのポート(56432)
3. ECS タスクの特定
3-1. タスク一覧を取得
TASK_VALUE=`aws ecs list-tasks --cluster ${CLUSTER} --region ${REGION}`
ECSで動いているタスクのARNを取得しています。
3-2. 最初のタスクのARNを抽出
TASK_ARN=`echo "${TASK_VALUE}" | jq '.taskArns[0]' | jq -r .`
リストの先頭を取っています。(代表タスクとして扱う)
3-3. 上記タスクの詳細を取得
RUNTIMEID_VALUE=`aws ecs describe-tasks ...`
3-4.コンテナの中からruntimeIdを探す
JSON_LEN=`echo "${RUNTIMEID_VALUE}" | jq '.tasks[0].containers' | jq length`
for i in `seq 0 $((${JSON_LEN} - 1))`; do
ROW=`echo "${RUNTIMEID_VALUE}" | jq ".tasks[0].containers[${i}]" | jq -r .`
IMAGE=`echo ${ROW} | jq -r .image`
if [ ${IMAGE} != 'null' ]; then
RUNTIMEID=`echo ${ROW} | jq -r .runtimeId`
fi
done
ECS Exec / SSM PortForwarding を行うためにはruntimeIdが必要とのこと。
タスク内のコンテナ一覧から、画像(image)が nullでないコンテナを探し、runtimeIdを取得しています。
4. AWS SSM Session のターゲットを作成
TASKID=(${RUNTIMEID//-/ })
START_SESSION_TARGET="ecs:${CLUSTER}_${TASKID}_${RUNTIMEID}"
ECS Exec用のSession Managerターゲット名を生成します。
ECSの特殊なフォーマットに合わせSession Target名を組み立てます。
5. SSMポートフォワーディングを実行
aws ssm start-session \
--target ${START_SESSION_TARGET} \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters "{\"host\":[\"${DB_HOST}\"],\"portNumber\":[\"${DB_PORT}\"], \"localPortNumber\":[\"${PORTFORWARD_PORT}\"]}" \
--region ${REGION}
ローカルPCの56432 → AWS内DB5432のトンネルを作る部分になります。
自分ののPC localhost:56432
↓(SSMトンネル)
AWS 内部の test-host:5432(PostgreSQL)
となります。
これによりローカルからAWS内部のDBにアクセスできるようになります。
引用・参考サイト