portfoward設定をスクリプト化する

# 作った背景

- 開発エンジニアがRDSにportfowardingする環境が増えた
- SSH接続はセキュリティ上リスクが高いので今後やめていきたい
- デプロイされたEC2インスタンスのインスタンスIDがコロコロ変わるので調査に一手間がかかりそう
- RDSのエンドポイントの入力に手間がかかる

# 前提条件

1. クレデンシャルキーは各自で設定しておくこと保存すること

2. スクリプト使用前に権限を変更しておくこと

```jsx
chmod +x portfowarding-rds-instance.sh
chmod +x portfowarding-rds-cluster.sh
chmod +x portfowarding.sh
```

# スクリプト（RDSクラスター版）

- 前提としてリージョンは固定しています。　ap-northeast-1
- 前提としてRDSクラスターの環境にのみ使います。
- プロファイル名を読み込み、踏み台となるEC2インスタンス名、RDSクラスター名を参照する。

```portfowarding-rds-cluster.sh
#!/bin/bash

# 利用可能なAWSプロファイルのリストを表示
echo "利用可能なAWSプロファイル:"
aws configure list-profiles

# AWSプロファイル名の入力を求める
read -p "利用するAWSプロファイル名を入力してください: " AWS_PROFILE

# AWSリージョンを指定
AWS_REGION="ap-northeast-1"

# EC2インスタンス名のリストを取得
echo "利用可能なEC2インスタンス (起動中):"
aws ec2 describe-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --filters "Name=instance-state-name,Values=running" --query 'Reservations[*].Instances[*].Tags[?Key==`Name`].Value' --output text

# ユーザーにEC2インスタンス名を選択させる
read -p "利用するEC2インスタンス名を入力してください: " INSTANCE_NAME

# RDSクラスター名のリストを取得
echo "利用可能なRDSクラスター:"
aws rds describe-db-clusters --profile ${AWS_PROFILE} --region ${AWS_REGION} --query 'DBClusters[*].DBClusterIdentifier' --output text

# ユーザーにRDSクラスター名を選択させる
read -p "利用するRDSクラスター名を入力してください: " RDS_CLUSTER_IDENTIFIER

# インスタンスIDを取得
INSTANCE_ID=$(aws ec2 describe-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --filters "Name=tag:Name,Values=${INSTANCE_NAME}" --query "Reservations[*].Instances[*].InstanceId" --output text)

# インスタンスIDが取得できなかった場合の処理
if [ -z "$INSTANCE_ID" ]; then
  echo "インスタンスIDが取得できませんでした。インスタンス名を確認してください。"
  exit 1
fi

# RDSクラスターエンドポイントを取得
RDS_ENDPOINT=$(aws rds describe-db-clusters --profile ${AWS_PROFILE} --region ${AWS_REGION} --db-cluster-identifier ${RDS_CLUSTER_IDENTIFIER} --query "DBClusters[0].Endpoint" --output text)

# RDSエンドポイントが取得できなかった場合の処理
if [ -z "$RDS_ENDPOINT" ]; then
  echo "RDSエンドポイントが取得できませんでした。RDSクラスター識別子を確認してください。"
  exit 1
fi

# ポートフォワーディングセッションの開始
aws ssm start-session --profile ${AWS_PROFILE} --region ${AWS_REGION} \
    --target ${INSTANCE_ID} \
    --document-name AWS-StartPortForwardingSessionToRemoteHost \
    --parameters "{\"host\":[\"${RDS_ENDPOINT}\"],\"portNumber\":[\"3306\"], \"localPortNumber\":[\"3306\"]}"
```

# スクリプト（RDSインスタンス版）

- 前提としてリージョンは固定しています。　ap-northeast-1
- 前提としてRDSインスタンスの環境にのみ使います
- プロファイル名を読み込み、踏み台となるEC2インスタンス名、RDSインスタンス名を参照する

```portfowarding-rds-instance.sh
#!/bin/bash

# 利用可能なAWSプロファイルのリストを表示
echo "利用可能なAWSプロファイル:"
aws configure list-profiles

# AWSプロファイル名の入力を求める
read -p "利用するAWSプロファイル名を入力してください: " AWS_PROFILE

# AWSリージョンを指定
AWS_REGION="ap-northeast-1"

# EC2インスタンス名のリストを取得
echo "利用可能なEC2インスタンス (起動中):"
aws ec2 describe-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --filters "Name=instance-state-name,Values=running" --query 'Reservations[*].Instances[*].Tags[?Key==`Name`].Value' --output text

# ユーザーにEC2インスタンス名を選択させる
read -p "利用するEC2インスタンス名を入力してください: " INSTANCE_NAME

# RDSインスタンス名のリストを取得
echo "利用可能なRDSインスタンス:"
aws rds describe-db-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --query 'DBInstances[*].DBInstanceIdentifier' --output text

# ユーザーにRDSインスタンス名を選択させる
read -p "利用するRDSインスタンス名を入力してください: " RDS_INSTANCE_IDENTIFIER

# インスタンスIDを取得
INSTANCE_ID=$(aws ec2 describe-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --filters "Name=tag:Name,Values=${INSTANCE_NAME}" --query "Reservations[*].Instances[*].InstanceId" --output text)

# インスタンスIDが取得できなかった場合の処理
if [ -z "$INSTANCE_ID" ]; then
  echo "インスタンスIDが取得できませんでした。インスタンス名を確認してください。"
  exit 1
fi

# RDSエンドポイントを取得
RDS_ENDPOINT=$(aws rds describe-db-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --db-instance-identifier ${RDS_INSTANCE_IDENTIFIER} --query "DBInstances[0].Endpoint.Address" --output text)

# RDSエンドポイントが取得できなかった場合の処理
if [ -z "$RDS_ENDPOINT" ]; then
  echo "RDSエンドポイントが取得できませんでした。RDSインスタンス名を確認してください。"
  exit 1
fi

# ポートフォワーディングセッションの開始
aws ssm start-session --profile ${AWS_PROFILE} --region ${AWS_REGION} \
    --target ${INSTANCE_ID} \
    --document-name AWS-StartPortForwardingSessionToRemoteHost \
    --parameters "{\"host\":[\"${RDS_ENDPOINT}\"],\"portNumber\":[\"3306\"], \"localPortNumber\":[\"3306\"]}"
```


# 注意

下記SSMポートフォワードのIAMにてSSM以外にポリシーの追加が必要になります。
これを設定しておかないと権限がないことでエラーが出ます。

- **AmazonEC2ReadOnlyAccess**
- **AmazonRDSReadOnlyAccess**


# スクリプト（RDSクラスター＆インスタンス マージ版）

```portfowarding.sh
#!/bin/bash

# 利用可能なAWSプロファイルのリストを表示
echo "利用可能なAWSプロファイル:"
aws configure list-profiles

# AWSプロファイル名の入力を求める
read -p "利用するAWSプロファイル名を入力してください: " AWS_PROFILE

# AWSリージョンを指定
AWS_REGION="ap-northeast-1"

# EC2インスタンス名のリストを取得
echo "利用可能なEC2インスタンス (起動中):"
aws ec2 describe-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --filters "Name=instance-state-name,Values=running" --query 'Reservations[*].Instances[*].Tags[?Key==`Name`].Value' --output text

# ユーザーにEC2インスタンス名を選択させる
read -p "利用するEC2インスタンス名を入力してください: " INSTANCE_NAME

# RDSがクラスターかインスタンスかを質問
read -p "RDSはクラスターですか？(yes/no): " IS_CLUSTER

if [ "$IS_CLUSTER" == "yes" ]; then
  # RDSクラスター名のリストを取得
  echo "利用可能なRDSクラスター:"
  aws rds describe-db-clusters --profile ${AWS_PROFILE} --region ${AWS_REGION} --query 'DBClusters[*].DBClusterIdentifier' --output text

  # ユーザーにRDSクラスター名を選択させる
  read -p "利用するRDSクラスター名を入力してください: " RDS_CLUSTER_IDENTIFIER

  # RDSクラスターエンドポイントを取得
  RDS_ENDPOINT=$(aws rds describe-db-clusters --profile ${AWS_PROFILE} --region ${AWS_REGION} --db-cluster-identifier ${RDS_CLUSTER_IDENTIFIER} --query "DBClusters[0].Endpoint" --output text)

  # RDSエンドポイントが取得できなかった場合の処理
  if [ -z "$RDS_ENDPOINT" ]; then
    echo "RDSエンドポイントが取得できませんでした。RDSクラスター識別子を確認してください。"
    exit 1
  fi
else
  # RDSインスタンス名のリストを取得
  echo "利用可能なRDSインスタンス:"
  aws rds describe-db-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --query 'DBInstances[*].DBInstanceIdentifier' --output text

  # ユーザーにRDSインスタンス名を選択させる
  read -p "利用するRDSインスタンス名を入力してください: " RDS_INSTANCE_IDENTIFIER

  # RDSインスタンスエンドポイントを取得
  RDS_ENDPOINT=$(aws rds describe-db-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --db-instance-identifier ${RDS_INSTANCE_IDENTIFIER} --query "DBInstances[0].Endpoint.Address" --output text)

  # RDSエンドポイントが取得できなかった場合の処理
  if [ -z "$RDS_ENDPOINT" ]; then
    echo "RDSエンドポイントが取得できませんでした。RDSインスタンス名を確認してください。"
    exit 1
  fi
fi

# インスタンスIDを取得
INSTANCE_ID=$(aws ec2 describe-instances --profile ${AWS_PROFILE} --region ${AWS_REGION} --filters "Name=tag:Name,Values=${INSTANCE_NAME}" --query "Reservations[*].Instances[*].InstanceId" --output text)

# インスタンスIDが取得できなかった場合の処理
if [ -z "$INSTANCE_ID" ]; then
  echo "インスタンスIDが取得できませんでした。インスタンス名を確認してください。"
  exit 1
fi

# ポートフォワーディングセッションの開始
aws ssm start-session --profile ${AWS_PROFILE} --region ${AWS_REGION} \
    --target ${INSTANCE_ID} \
    --document-name AWS-StartPortForwardingSessionToRemoteHost \
    --parameters "{\"host\":[\"${RDS_ENDPOINT}\"],\"portNumber\":[\"3306\"], \"localPortNumber\":[\"3306\"]}"
```



RDSクラスターですが、下記コマンドでもRDSクラスターのエンドポイントは取得できるようです。
```
aws rds describe-db-instances
```