SecretsManagerでRDSのパスワードを管理するときのあれこれ

# この記事について
AWS SecretsManagerでRDSのDB認証情報を管理した際に調査した仕様についてまとめたものになります。私が調査したとき、まあまあ大変だったので記録しておきます。
本記事の内容としては同じような調査する方向けに資料をまとめたものになります。
基本となる環境の構築はこちらの記事を参考にしています。
[AWS Secrets Managerで RDSのパスワードローテーションしてみる in 2022](https://dev.classmethod.jp/articles/secrets-manager-password-rotation-2022/)

# 目次
* [RDSのマスターユーザーのパスワードを管理する](#rdsのマスターユーザーのパスワードを管理する)
* [Lambdaローテーション関数の詳細](#lambdaローテーション関数の詳細)
* [SecretsManagerのリソースの即時削除](#secretsmanagerのリソースの即時削除)
* [SecretsManagerのローテーションがうまくいかないとき](#secretsmanagerのローテーションがうまくいかないとき)

## RDSのマスターユーザーのパスワードを管理する
参考ページの方法でも管理できるのですが、RDS構築時に「マスターユーザーの認証情報の設定」の項目があります。
ここから画像のように、"マスターユーザー名","認証情報管理","暗号化キー"を設定しRDSを構築します。<br>
![マスターユーザーの認証情報の設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848985/96ca8041-cefa-3240-36c0-aed90177a858.png)


構築後にSecretsManagerを確認すると以下のような **rds!** から始まるリソースが作成されることが確認できます。<br>
![SecretsManagerリソース](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848985/9b931fc9-3939-72fe-76e9-c15d32bc4bc2.png)

このシークレットのローテーションはRDSで管理されます。
通常のSecretsManagerのローテーションと異なりLambda関数が生成されないため、Lambdaを管理する必要が無くなります。
ただし、通常と同様にローテーションスケジュールや認証情報の値の参照はSecretsManagerから行えるので、環境変数を用いたログインなどは通常通り行えます。
![シークレットのローテーション設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848985/d042e224-0cc1-7dcb-0970-1977d3ebb975.png)


## Lambdaローテーション関数の詳細
SecretsManagerによって生成されるLambda関数のソースコードは以下の公式ドキュメントにまとめられています。
[AWS Secrets Manager ローテーション関数のテンプレート](https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-postgre-singleuser)

こちらのドキュメントよりソースコードを参照することで、SecretsManagerのパスワードで自動生成されるパスワードの仕様を確認することが出来ます。
`Amazon RDS および Amazon Aurora MySQL シングルユーザー`の時に生成されるソースコードを例として参照すると、下の方の行に以下の記載が確認できます。
```
    passwd = service_client.get_random_password(
        ExcludeCharacters=os.environ.get('EXCLUDE_CHARACTERS', '/@"\'\\'),
        PasswordLength=int(os.environ.get('PASSWORD_LENGTH', 32)),
        ExcludeNumbers=get_environment_bool('EXCLUDE_NUMBERS', False),
        ExcludePunctuation=get_environment_bool('EXCLUDE_PUNCTUATION', False),
        ExcludeUppercase=get_environment_bool('EXCLUDE_UPPERCASE', False),
        ExcludeLowercase=get_environment_bool('EXCLUDE_LOWERCASE', False),
        RequireEachIncludedType=get_environment_bool('REQUIRE_EACH_INCLUDED_TYPE', True)
    )
```
ここには生成されるパスワードのデフォルトの条件が記載されています。
それぞれの条件は下記の内容となります。
| 環境変数 | 詳細 | デフォルトの設定 |
|:---------:|:------------:|:------------:|
| EXCLUDE_CHARACTERS | 除外する文字 | :/@"'\ |
| PASSWORD_LENGTH | パスワード長 | 32 |
| EXCLUDE_NUMBERS | 数字の除外 | False |
| EXCLUDE_PUNCTUATION | 句読点の除外 | False |
| EXCLUDE_UPPERCASE | 大文字の除外 | False |
| EXCLUDE_LOWERCASE | 小文字の除外 | False |
| REQUIRE_EACH_INCLUDED_TYPE | 生成されるパスワードが<br>許可された文字タイプを<br>1つ以上含めるかを指定 | True |

これらの条件はソースコードを直接編集することでも変更できるのですが、画像のようにLambdaの環境変数から変更することもできます。

![スクリーンショット 2025-02-07 161833.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848985/f38da8a9-87b3-83dc-fec7-3980f1455c53.png)


## SecretsManagerのリソースの即時削除
SecretsManagerのリソースはコンソール画面から場合、通常7日程必要となります。(保留期間として、誤って操作した際のリストアが可能)
「でも、テストのためだけに作ったからすぐに消していいんだよなぁ」となることもあると思います。
その場合は下記コマンドをSecretsManagerを運用しているアカウントのCloudShellから入力することで、即時削除ができます。
ただし、通常存在する保留期間も無くなるため要注意です。
```
$ aws secretsmanager delete-secret \
   --secret-id "SecretsManager-name" \
   --force-delete-without-recovery
```

## SecretsManagerのローテーションがうまくいかないとき
下記リンク先におおよその原因がまとめられているのですが、そこに記載が無く陥った問題と原因を紹介します。

[AWS Secrets Managerでシークレットが正常にローテーションできなかった時の対応方法](https://dev.classmethod.jp/articles/what-to-do-when-secrets-cannot-be-rotated-successfully-in-aws-secrets-manager/)

##### SecretsManagerからローテーション用Lambda関数が作成できない
SecretsManagerのローテーション設定はCloudFormationを経由して自動的にLambda関数を生成します。その際に下記画像のように`ローテーションリソースを作成しようとして、AWS CloudFormationで問題が発生しました。`とエラーの発生する場合があります。
![SecM1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848985/194edbba-bfa9-c514-39d6-bbf834586213.png)

RDSの作成時に自動で作成されるサブネットグループを利用した場合、wavelength zoneにサブネットを自動作成する場合があります。この時、自動で作成されたwavelength zoneのサブネットにLambda関数をデプロイしようとすることが原因でこのようなエラーの発生する場合があります。Lambdaはwavelength zoneに対応していないため、CloudFormationで作成できずエラーとなります。

wavelength zoneに対応したサービスは以下の公式QAにまとめられています。
[wavelength zone対応サービス](https://aws.amazon.com/jp/wavelength/faqs/)

# 参考URLまとめ
* [AWS Secrets Managerで RDSのパスワードローテーションしてみる in 2022](https://dev.classmethod.jp/articles/secrets-manager-password-rotation-2022/)
* [AWS Secrets Manager ローテーション関数のテンプレート](https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/reference_available-rotation-templates.html#sar-template-postgre-singleuser)
* [AWS Secrets Managerでシークレットが正常にローテーションできなかった時の対応方法](https://dev.classmethod.jp/articles/what-to-do-when-secrets-cannot-be-rotated-successfully-in-aws-secrets-manager/)