RDS Proxy+RDS(MySQL)の接続について

## 概要
RDSとRDS Proxyの接続の手順やエラーの解消についてメモです。

## RDS Proxy(MySQL)について

### 制約

#### 使えるリージョン
- 米国東部 (バージニア北部)
- 米国東部 (オハイオ)
- 米国西部 (北カリフォルニア)
- 米国西部 (オレゴン)
- アジアパシフィック (ムンバイ)
- アジアパシフィック (ソウル)
- アジアパシフィック (シンガポール)
- アジアパシフィック (シドニー)
- アジアパシフィック (東京)
- カナダ (中部)
- 欧州 (フランクフルト)
- 欧州 (アイルランド)
- 欧州 (ロンドン)

#### 対象RDSのMySQLバージョン
MySQL 5.6/5.7
**MySQL 8.0では使用不可です**

#### アクセス
接続対象のデータベースと同一VPCに設置する必要があります。
プロキシはパブリックアクセス出来ないため、Lambdaと接続する場合はLambdaも同じVPCに設置する。

### ピン留め

RDSProxyでは、接続が特定のクライアントに固定され、セッション終了まで他のクラアントからの接続が行えなくなる状態に陥ることがあり、
これが発生すると接続をうまいことさばいてくれるRDS proxyの意味がなくなってしまいます。

#### 発生する条件

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/rds-proxy.html#rds-proxy-pinning
> RDS Proxy は、文字セット、照合順序、タイムゾーン、自動コミット、現在のデータベース、SQL モード、および session_track_schema の各設定への変更を追跡します。したがって、これらの変更時に RDS Proxy はセッションをピン留めしません。この場合、RDS Proxy は、これらの設定の値が同じである他のセッションでのみ、接続を再利用します

- `SET`、`SELECT`コマンドでの変数の変更
- `LOCK TABLE`、`LOCK TABLES`コマンド
- 一時テーブルの作成

等がピン留めの原因になります。

ピン留めを回避するパラメータについては別にまとめたいと思います。


## 手順

### 大まかな流れ


### VPC・RDS作成する
省略します。
RDSはRDS Proxyの制約に合ったものを作ります。

セキュリティグループを作成してRDSに割り当てておきます。(sg-rds)


### AWS Secrets Manager でデータベース認証情報を作成
ユーザー名とパスワードの認証情報をSecrets Managerに保存する

usernameとpasswordのフィールドに接続したいRDSの情報と一致するように登録する

`AWS Secrets Manager > シークレット > 新しいシークレットを保存する`

![](https://i.imgur.com/YF59uPi.png)

AWS CLIで作成する場合

```
$ aws secretsmanager create-secret
--name "secret_name"
--description "secret_description"
--region region_name
--secret-string '{"username":"db_user","password":"db_user_password"}'
```


### IAMロールの作成

新規作成

`RDS > Add Role to Database`

ポリシーの作成

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": [
            // 複数ある場合は複数
                "作成したシークレットのARN",
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "kms:Decrypt",
            "Resource": "KMSのARN",
            "Condition": {
                "StringEquals": {
                    "kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
                }
            }
        }
    ]
}
```

KMSのARNは特に設定していない場合、
`Key Management Service (KMS) > AWS マネージド型キー > aws/secretsmanager`
を使用します。

### RDS Proxyを作成

コンソールより作成

![スクリーンショット 2020-09-28 19.04.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489139/03aa30b8-d64f-985c-f094-522b3cacdc0a.png)

プロキシ識別子 > RDS Proxyに名前を付けます
エンジンの互換性 > 今回はMySQL

![スクリーンショット 2020-09-28 19.04.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489139/636bd1e4-3909-85d4-befb-cfe45e053281.png)

データベース > 作成した対象のRDSを選択します
接続プールの最大接続数 > とりあえずデフォルトのままに

![スクリーンショット 2020-09-28 19.29.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489139/9185a7a5-29b4-6d8b-dcfc-9bb56210120a.png)


Secrets Manager シークレット > 先ほど作成したシークレットを設定
IAM ロール > 先ほど作成したIAMロールを設定
IAM認証 > 今回は無効にします
サブネット > RDSに割り当てたサブネットグループと同じ物を選択します

![スクリーンショット 2020-09-28 19.19.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489139/517ca609-d814-9cc8-62f5-209cad081dde.png)

VPCセキュリティグループ > 新規作成。分かりやすい名前を付けます(sg-rdsproxy)

「プロキシを作成」

### セキュリティグループ
`EC2 > セキュリティグループ > [セキュリティグループ] > インバウンドルールを編集`
RDSのセキュリティグループ(sg-rds)の設定で、RDS Proxyのセキュリティグループ(sg-rdsproxy)からのインバウンドを許可します。

| | | | |
| ---- | ---- | ---- | ---- |
|  MYSQL/Aurora  |  TCP  | 3306  | sg-rdsproxy |




ステータスが「利用可能」になったら完了です。

## 「接続不可」になるとき


このコマンドで接続不可の理由をチェック出来きます。
参考：https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/rds-proxy.html#rds-proxy-verifying

```
$aws rds describe-db-proxy-targets --db-proxy-name
```


### エラー例1

```
"TargetHealth": {
    "State": "UNAVAILABLE",
    "Reason": "PENDING_PROXY_CAPACITY",
    "Description": "DBProxy Target unavailable due to an internal error"
}
```

> プロキシがスケーリングオペレーションを完了した後で、接続を再試行します

20分ぐらい待ってから確認してみます。

### エラー例2

```
"TargetHealth": {
    "State": "UNAVAILABLE",
    "Description": "DBProxy Target unavailable due to an internal error"
}
```

セキュリティグループの設定に問題がないか確認してみる。

### エラー例3

```
"TargetHealth": {
    "State": "UNAVAILABLE",
    "Reason": "AUTH_FAILURE",
    "Description": "Proxy does not have any registered credentials"
}
```

IAMロールに問題が無いか確認。

### エラー例4

```
"TargetHealth": {
    "State": "UNAVAILABLE",
    "Reason": "AUTH_FAILURE",
    "Description": "Database authentication failed with provided user credentials"
}
```

シークレットの設定に問題が無いか確認。

### OK

```
"TargetHealth": {
    "State": "AVAILABLE"
}
```