【NLB/RDS】ローカル環境からプライベートサブネットに存在するRDSに接続する方法

# はじめに
外部サービスやローカル環境からプライベートサブネットに配置しているRDSへ、接続したい要件に対して調査していたところクラスメソッドさんの記事でNLBを使うことで実現できることを知り、こちらの内容を元に設定していきました。

記事にも書いてある通り、構築する上で何点か問題がありそれぞれ対応したことを記述しています。

https://dev.classmethod.jp/articles/nlb-bastion-for-rds/

# 構成図
![スクリーンショット 2022-05-27 0.41.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230985/5001d32c-6c20-2579-d3d3-585ec0bcdaf8.png)

# Network Load Balancerとは
TCP,UDP等のプロトコルでの負荷分散を行うことができるロードバランサーです。
Application Load Balancerと比較すると下記の特徴があります。

|  |ALB |NLB  |
|---|---|---|
|レイヤー  |7  |4  |
|プロトコル|HTTP(S)|TCP,UDP,TCP_UDP,TLS|
|セキュリティグループ  |設定可能  |設定不可能  |
|クライアントIPアドレスの保持  |設定不可能  |設定可能  |
|送信元ポート  |ALBのもの  |保持可能  |
|アクセスログ保管  |全て対応  |TLSのみ  |


※下記記事がとても参考になりました。
　今回構築する上で気になった項目を抜粋しています。

https://cloud5.jp/alb-nlb/

# NLBとRDSを連携する上での注意点
### セキュリティグループを設定することができない
NLBではセキュリティグループを設定することができないため、リクエストは全てターゲット（RDS）のセキュリティグループで対応する必要があります。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/security-group-load-balancer/

### クライアントIPアドレスを保持する設定が必要
セキュリティグループを設定し疎通ができることを確認しましたが、想定外のIPからもアクセスできることがわかりました。

NLBを経由していたことで**NLB**の**プライベート IP アドレス**がクライアントIPとなりアクセスが可能となっていたようでした。

この状態だとNLBのDNS名がわかれば誰でも接続できてしまいます。
想定しているIPアドレスのみ許可したい場合は、NLBのターゲットグループ に「クライアントのIPアドレスを保持する」の項目にチェックを入れる必要があるようです。


![スクリーンショット 2022-05-27 0.58.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230985/9ccee19d-1fc2-db9a-5734-710fe513ec30.png)

https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/load-balancer-target-groups.html#:~:text=%E3%81%AF%20source_ip%20%E3%81%A7%E3%81%99%E3%80%82-,%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%20IP%20%E3%81%AE%E4%BF%9D%E5%AD%98,-Network%20Load%20Balancer

### RDSのIPアドレスが変わってしまった場合再設定が必要
NLBを使用してRDSに接続するためには、ターゲットをIPにする必要があります。
RDSがフェイルオーバー等で、プライベートIPアドレスが変わってしまうと接続できなくなるため手動でNLBのターゲットIPアドレスを変更しなければいけません。

今回は、手動で設定するのはとても面倒なので、`AWS CLI`を使用して自動でIPアドレスを再設定するスクリプトを作りました。

#### IPアドレスの再設定を行うスクリプト
```shell
#!/bin/sh

## 固定値
### リージョンの設定
TARGET_REGION=リージョン名
echo ${TARGET_REGION}
### ポート番号の設定
TARGET_PORT=RDSのポート番号
echo ${TARGET_PORT}
### ターゲットグループ名設定
TARGET_GROUP_NAME=ターゲットグループ名
echo ${TARGET_GROUP_NAME}

## RDSから情報を取得して設定
### IPアドレスを取得
RDS_PRIVATE_IP=`nslookup RDSのエンドポイント | grep Address |  tail -n +2 | cut -f2 -d ' '`
echo ${RDS_PRIVATE_IP}

### RDSからアベイラビリティゾーンの情報を取得
RDS_AVAILABILITY_ZONE=`aws rds describe-db-instances \
                       --db-instance-identifier DB識別子 \
                       --query "DBInstances[].[AvailabilityZone]" \
                       --output text --region ${TARGET_REGION} | column -t`
echo ${RDS_AVAILABILITY_ZONE}

## NLBから情報を取得して設定
### ターゲットグループのarnを取得
TARGET_GROUP_ARN=`aws elbv2 describe-target-groups --query "TargetGroups[].TargetGroupArn"  --output text --name ${TARGET_GROUP_NAME} --region ${TARGET_REGION}`
echo ${TARGET_GROUP_ARN}
### ターゲットグループからIPアドレスを取得
TARGET_IP=`aws elbv2 describe-target-health \
           --target-group-arn ${TARGET_GROUP_ARN} \
           --query 'TargetHealthDescriptions[].Target.Id' --output text \
           --region ${TARGET_REGION}`
echo ${TARGET_IP}

### ターゲットグループからアベイラビリティゾーンの情報を取得
TARGET_AVAILABILITY_ZONE=`aws elbv2 describe-target-health \
                          --target-group-arn ${TARGET_GROUP_ARN} \
                          --query 'TargetHealthDescriptions[].Target.AvailabilityZone' --output text \
                          --region ${TARGET_REGION}`
echo ${TARGET_AVAILABILITY_ZONE}

# ターゲットグループに登録されているIPアドレスを解除
aws elbv2 deregister-targets \
--targets AvailabilityZone=${TARGET_AVAILABILITY_ZONE},Id=${TARGET_IP},Port=${TARGET_PORT} \
--target-group-arn ${TARGET_GROUP_ARN} \
--region ${TARGET_REGION}

# ターゲットグループに新しいIPアドレスを登録
aws elbv2 register-targets \
--targets AvailabilityZone=${RDS_AVAILABILITY_ZONE},Id=${RDS_PRIVATE_IP},Port=${TARGET_PORT} \
--target-group-arn ${TARGET_GROUP_ARN} \
--region ${TARGET_REGION}
```

# 検証
RDSをフェイルオーバーで再起動を行い、スクリプトを実行します。
NLBのターゲットグループからIPアドレスが更新されローカルのクライアントツールからも問題なく接続できました。

# 参考URL
https://qiita.com/kurono/items/71814097531ed32efd55

https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/load-balancer-target-groups.html#client-ip-preservation

https://qiita.com/zakky/items/34be198d1816e99d7a1a#49-%E3%82%BF%E3%83%BC%E3%82%B2%E3%83%83%E3%83%88%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E5%B1%9E%E6%80%A7%E5%A4%89%E6%9B%B4-modify-target-group-attributes

https://blog.serverworks.co.jp/aws-cli-elbv2-create

https://blog.serverworks.co.jp/aws-cli-rds

https://kakakakakku.hatenablog.com/entry/2017/04/22/233836

https://docs.aws.amazon.com/cli/latest/reference/elbv2/deregister-targets.html

https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html