概要
前回はRDSと踏み台サーバを作成し、
SSMを使って踏み台サーバ上からのRDSへの接続を確認した。
今回は、ローカルのクライアントからポートフォワーディングしてRDSを操作することを試す。
環境
- Windows 10
- gitbash
- aws-cli/2.4.7 Python/3.8.8 Windows/10 exe/AMD64 prompt/off
検討
ぐぐったところ、ポートフォワーディングのアプローチは2つある模様。
鍵の管理が面倒そうなので、2の方法を行う。
- セッションマネージャーを使用して SSH トンネルを開始
- 「サーバに公開鍵の設定」 or 「EC2 InstanceConnectで一時的に公開鍵を設定」
- ポートフォワーディング+TCPリレー
- サーバにsocatのインストールが必要
- 2時間でポートフォワーディングが切れる
Session Managerを使ってEC2の先にあるRDSに接続してみたを参考に設定していく。
アーキテクチャ
まず、SSMのPort Forwardingだけでは、SSHトンネルのポートフォワーディングを行うことはできない。ポートフォワーディング先のEC2がリッスンしているポートのポートフォワーディングができるだけである。
そのため、EC2でリッスンしたポートをRDSへTCPリレーするように設定する。
ec2にsocatのインストール
cdkを修正
host.instance.addUserData(
'yum -y update',
'yum install -y postgresql jq',
+ 'yum install -y socat',
);
ec2でsocatを起動するSSMドキュメントの作成
踏み台サーバでsocatを有効にし、TCPリレーを行うためのコマンド。
AWS Systems Manager のSSM ドキュメントスキーマを定義して、起動の設定を行う。
ドキュメントの作成
---
schemaVersion: "2.2"
description: Port Forwarding
parameters:
localPort:
type: String
default: "5432"
mainSteps:
- action: aws:runShellScript
name: run
inputs:
runCommand:
- secret=$(aws secretsmanager get-secret-value --region ap-northeast-1 --secret-id db-secrets | jq .SecretString | jq fromjson)
- endpoint=$(echo $secret | jq -r .host)
- targetPort=$(echo $secret | jq -r .port)
- socat tcp4-listen:{{ localPort }},reuseaddr,fork TCP:$endpoint:$targetPort
#!/bin/bash
bin_dir=$(cd $(dirname $0) && pwd)
DOCUMENT_NAME=port-relay
# 再作成するときはいったん削除してから設定
# aws ssm delete-document \
# --name ${DOCUMENT_NAME}
cd $bin_dir && aws ssm create-document \
--content file://command-document.yml \
--name ${DOCUMENT_NAME} \
--document-type "Command" \
--document-format "YAML"
踏み台サーバのTCPリレー設定
作成したSSMコマンドを実行する
#!/bin/bash
DOCUMENT_NAME='port-relay'
INSTANCE_ID=$( aws ec2 describe-instances --filter "Name=instance-state-name,Values=running" "Name=tag:Name,Values=BastionHost" --query "Reservations[].Instances[].InstanceId" | jq -r '.[0]')
aws ssm send-command \
--instance-ids ${INSTANCE_ID} \
--document-name ${DOCUMENT_NAME}
ポートフォワーディングの開始
ポートフォワーディングを開始する。
#!/bin/bash
LOCAL_PORT=15432
SECRET_NAME=db-secrets
INSTANCE_ID=$( aws ec2 describe-instances --filter "Name=instance-state-name,Values=running" "Name=tag:Name,Values=BastionHost" --query "Reservations[].Instances[].InstanceId"| jq -r '.[0]')
SECRET=$(aws secretsmanager get-secret-value --region ap-northeast-1 --secret-id $SECRET_NAME | jq .SecretString | jq fromjson)
PASSWORD=$(echo $SECRET | jq -r .password)
USERNAME=$(echo $SECRET | jq -r .username)
PORT=$(echo $SECRET | jq -r .port)
# dbクライアントに設定する用の情報を表示
echo 'DB接続用情報(ポートフォワーディング)'
echo host= localhost
echo databasename= postgres
echo port= $LOCAL_PORT
echo username= $USERNAME
echo password= $PASSWORD
# ポートフォワーディング開始
aws ssm start-session \
--target ${INSTANCE_ID} \
--document-name AWS-StartPortForwardingSession \
--parameters portNumber=$PORT,localPortNumber=$LOCAL_PORT
確認
使用するDBクライアントを通じて接続を確認する。
今回はa5SQLを利用した。
参考
公式
AWS Systems Manager 経由で SSH トンネルを使用してプライベート VPC リソースにアクセスするにはどうすればよいですか?
手順8 :(オプション)SessionManagerを介したSSH接続のアクセス許可の有効化と制御
EC2 InstanceConnectを使用してLinuxインスタンスに接続
AWS System Manager Sessions Manager を使用した新しい機能 – Port Forwarding
SSM ドキュメントスキーマの機能と例
AWS Systems Manager とは
野生
CDKで作成した踏み台サーバにAWS SSM Session Manager と AWS Instance Connect を利用してSSH接続する
AWSにおける踏み台(Bastion)サーバーの作り方
セッションマネージャー over SSH 経由でプライベートサブネット内のRDSへ接続する方法
Session Manager と踏み台サーバの共存構成
Session Managerを使ってEC2の先にあるRDSに接続してみた
socatコマンドを利用した お手軽TCPリレー
AWS System Managerセッションマネージャーでポートフォワードする
さらば踏み台サーバ。Session Managerを使ってEC2に直接SSHする