AWS Secrets Managerでシークレットが正常にローテーションできなかった時の対応方法

AWS Secrets Managerのローテーションの仕組みを理解しよう
2022.03.28

シークレットのローテーションに失敗するのだが

こんにちは、のんピ(@non____97)です。

皆さんはAWS Secrets ManagerでDBのシークレットが正常にローテーションできなかった時はありますか? 私はあります。

シークレットをローテーションするLambda関数のログを確認してもイマイチ分かりにくかったりするので、勘所と対応方法をまとめます。

いきなりまとめ

  • シークレットのローテーションが上手く動作しない場合は、まずLambda関数とDBのセキュリティグループを確認
    • Lambda関数のセキュリティグループで、DBとAWS Secrets Managerにエンドポイントにアクセスを許可するルールがあるか
    • DBのセキュリティグループで、Lambda関数からのアクセスを許可するルールがあるか
  • シークレットをローテーションするLambda関数にAWS Secrets Managerのエンドポイントへのルートがあるかを確認
    • NAT Gatewayへのルーティング or AWS Secrets ManagerのVPCエンドポイント(PrivateLink)があるか
  • 上述の内容を実施しても正常にローテーションされない場合は、シークレットの各バージョンのラベルを確認して対応する
  • AWSPENDINGのラベルのバージョンにAWSCURRENTのラベルが付いていない場合
    • AWSPENDINGのラベルのバージョンを削除する
  • AWSPENDINGのラベルのバージョンにAWSCURRENTのラベルも付いている場合
    • AWSPENDINGAWSCURRENTのラベルが付与されているバージョンのシークレットでDBに接続できるか確認
    • AWSPENDINGAWSCURRENTのラベルが付与されているバージョンのシークレットでDBに接続できない場合、AWSPREVIOUSのラベルが付与されているバージョンのシークレットでDBに接続できるか確認
    • AWSPREVIOUSのラベルが付与されているバージョンのシークレットでDBに接続できる場合、AWSPREVIOUSラベルが付いているバージョンにAWSCURRENTラベルを付与する
    • AWSPENDINGAWSCURRENTのラベルが付与されているバージョンのシークレットでDBに接続できる場合、AWSPENDINGAWSCURRENTのラベルが付与されているバージョンでAWSPENDINGのラベルのみを外す

ローテーション失敗時に確認すること

ローテーションに失敗したかどうかの判断はシークレットをローテーションするLambda関数のログを確認します。シークレットのローテーションに失敗すると、以下のようなログが出力されます。

ローテーション失敗時のログの例1

START RequestId: 24ce3d1b-e194-482c-b33a-5d879e5d15d5 Version: $LATEST
[INFO]	2022-03-28T05:33:50.860Z	24ce3d1b-e194-482c-b33a-5d879e5d15d5	Found credentials in environment variables.
[INFO]	2022-03-28T05:33:52.139Z	24ce3d1b-e194-482c-b33a-5d879e5d15d5	createSecret: Successfully put secret for ARN arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx and version 4bcc57ad-6901-489f-88cf-c5b56f14cbca.
END RequestId: 24ce3d1b-e194-482c-b33a-5d879e5d15d5
REPORT RequestId: 24ce3d1b-e194-482c-b33a-5d879e5d15d5	Duration: 1548.10 ms	Billed Duration: 1549 ms	Memory Size: 128 MB	Max Memory Used: 73 MB	Init Duration: 318.95 ms	
START RequestId: f312a4c3-3d5f-45f2-aa67-a95e1985f993 Version: $LATEST
[ERROR]	2022-03-28T05:34:07.568Z	f312a4c3-3d5f-45f2-aa67-a95e1985f993	setSecret: Unable to log into database with previous, current, or pending secret of secret arn arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx
[ERROR] ValueError: Unable to log into database with previous, current, or pending secret of secret arn arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 76, in lambda_handler
    set_secret(service_client, arn, token)
  File "/var/task/lambda_function.py", line 169, in set_secret
    raise ValueError("Unable to log into database with previous, current, or pending secret of secret arn %s" % arn)
END RequestId: f312a4c3-3d5f-45f2-aa67-a95e1985f993
REPORT RequestId: f312a4c3-3d5f-45f2-aa67-a95e1985f993	Duration: 15393.85 ms	Billed Duration: 15394 ms	Memory Size: 128 MB	Max Memory Used: 73 MB

ローテーション失敗時のログの例2

START RequestId: 74fc027b-8dc0-4da4-b618-239b54b95247 Version: $LATEST
[INFO]	2022-03-28T02:38:08.558Z	74fc027b-8dc0-4da4-b618-239b54b95247	Found credentials in environment variables.
END RequestId: 74fc027b-8dc0-4da4-b618-239b54b95247
REPORT RequestId: 74fc027b-8dc0-4da4-b618-239b54b95247	Duration: 30032.43 ms	Billed Duration: 30000 ms	Memory Size: 128 MB	Max Memory Used: 71 MB	Init Duration: 372.84 ms	
2022-03-28T02:38:38.338Z 74fc027b-8dc0-4da4-b618-239b54b95247 Task timed out after 30.03 seconds

マネージメントコンソールの場合、シークレット「シークレット名」をローテーションできませんでした。 A previous rotation isn't complete. That rotation will be reattempted.と表示されたりもします。

A previous rotation isn't complete. That rotation will be reattempted

このようにシークレットを正しくローテーションできない場合は、まずシークレットをローテーションするLambda関数とDBのセキュリティグループを確認します。

ポイントは以下の2つです。

  1. Lambda関数のセキュリティグループで、DBとAWS Secrets Managerにエンドポイントにアクセスを許可するルールがあるか
  2. DBのセキュリティグループで、Lambda関数からのアクセスを許可するルールがあるか

もし、両方のポイントを満たせていない場合は、こちらを満たすようなルールを追加します。意外とLambda関数のアウトバウンドルールで、AWS Secrets Managerにエンドポイントにアクセスを許可するルールがなかったりするので注意して確認しましょう。

加えて、シークレットをローテーションするLambda関数にAWS Secrets Managerのエンドポイントへのルートがあるかも確認します。Lambda関数が動作するサブネットにNAT Gatewayへのルーティングがあるか、もしくはVPCにAWS Secrets ManagerのVPCエンドポイント(PrivateLink)があるかを確認します。

どちらも存在しない場合は、Lambda関数のサブネットのルートテーブルにNAT Gatewayへのルーティングを追加するなど、Lambda関数からAWS Secrets Managerのエンドポイントへのルートを用意します。

上述の確認ポイントはAWS公式ドキュメントでも紹介されています。

以上の対応をすれば、基本的に次回から正しくローテーションされます。

それでもローテーションが上手くいかない場合

それでもローテーションが上手くいかない場合もあります。

例えば、新しいシークレットは生成したが、DBに新しいシークレットを反映できていない場合です。

そのような場合は、シークレットをローテーションするLambda関数のCloudWatch Logsに以下のようなエラーが出力されます。

START RequestId: 24ce3d1b-e194-482c-b33a-5d879e5d15d5 Version: $LATEST
[INFO]	2022-03-28T05:33:50.860Z	24ce3d1b-e194-482c-b33a-5d879e5d15d5	Found credentials in environment variables.
[INFO]	2022-03-28T05:33:52.139Z	24ce3d1b-e194-482c-b33a-5d879e5d15d5	createSecret: Successfully put secret for ARN arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx and version 4bcc57ad-6901-489f-88cf-c5b56f14cbca.
END RequestId: 24ce3d1b-e194-482c-b33a-5d879e5d15d5
REPORT RequestId: 24ce3d1b-e194-482c-b33a-5d879e5d15d5	Duration: 1548.10 ms	Billed Duration: 1549 ms	Memory Size: 128 MB	Max Memory Used: 73 MB	Init Duration: 318.95 ms	
START RequestId: f312a4c3-3d5f-45f2-aa67-a95e1985f993 Version: $LATEST
[ERROR]	2022-03-28T05:34:07.568Z	f312a4c3-3d5f-45f2-aa67-a95e1985f993	setSecret: Unable to log into database with previous, current, or pending secret of secret arn arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx
[ERROR] ValueError: Unable to log into database with previous, current, or pending secret of secret arn arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 76, in lambda_handler
    set_secret(service_client, arn, token)
  File "/var/task/lambda_function.py", line 169, in set_secret
    raise ValueError("Unable to log into database with previous, current, or pending secret of secret arn %s" % arn)
END RequestId: f312a4c3-3d5f-45f2-aa67-a95e1985f993
REPORT RequestId: f312a4c3-3d5f-45f2-aa67-a95e1985f993	Duration: 15393.85 ms	Billed Duration: 15394 ms	Memory Size: 128 MB	Max Memory Used: 73 MB

エラーが発生しても、しばらくは自動でローテーションをリトライしてくれますが、原因を解消せずに10分ほど経つとリトライもされなくなります。

このような状態で手動でローテーションをしようとしてもシークレット「シークレット名」をローテーションできませんでした。 A previous rotation isn't complete. That rotation will be reattempted.と表示されてしまいます。

このような場面に遭遇したら、シークレットの各バージョンのラベルを確認します。

シークレットのバージョン一覧は、AWS CLIでlist-secret-version-idsを実行して確認します。

実行結果は以下の通りです。

$ aws secretsmanager list-secret-version-ids \
>   --secret-id prd-db-cluster/AdminLoginInfo
{
    "Versions": [
        {
            "VersionId": "dfe186d3-7399-4f46-873a-a4f7078aa77f",
            "VersionStages": [
                "AWSPENDING"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T09:59:44.672000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        },
        {
            "VersionId": "c7264842-7f5d-407a-9b8e-24e63385e62a",
            "VersionStages": [
                "AWSCURRENT"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T09:50:12.998000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        },
        {
            "VersionId": "8db5d941-83e3-48bc-b63c-adcb714da48d",
            "VersionStages": [
                "AWSPREVIOUS"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T09:50:06.006000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        }
    ],
    "ARN": "arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx",
    "Name": "prd-db-cluster/AdminLoginInfo"
}

この状態は以下AWS公式ドキュメントで言うところのステップ 2: データベースまたはサービスの認証情報を変更する (setSecret)が上手くいっていない状態です。

ステップ 1: シークレットの新しいバージョンを作成する (createSecret)
ローテーションの最初のステップでは、シークレットの新しいバージョンが作成されます。ローテーション戦略に基づき、この新しいバージョンには新しいパスワード、新しいユーザー名とパスワード、またはそれ以上の秘密情報を含めることができます。Secrets Manager は、この新しいバージョンに対し、ステージングラベル AWSPENDING をラベル付けします。

ステップ 2: データベースまたはサービスの認証情報を変更する (setSecret)
次に、AWSPENDING バージョンのシークレットと一致するよう、データベースまたはサービス内の認証情報が、ローテーションにより変更されます。このステップでは、ローテーション戦略に応じて、既存のユーザーと同じアクセス許可を付与しながら、新しいユーザーを作成できます。

ローテーションの仕組み - AWS Secrets Manager

そのため、DBには新しいバージョンのシークレット(AWSPENDING)は適用されていない状態です。

このバージョンのシークレット(AWSPENDING)はDBに適用されていない不要なバージョンであるため削除をします。シークレットのラベルの操作をする場合は、AWS CLIでupdate-secret-version-stageを実行します。

コマンドの実行結果は以下の通りです。

# AWSPENDING のラベルが付いているバージョンを削除
$ aws secretsmanager update-secret-version-stage \
   --secret-id prd-db-cluster/AdminLoginInfo \
   --version-stage AWSPENDING \
   --remove-from-version-id dfe186d3-7399-4f46-873a-a4f7078aa77f
{
    "ARN": "arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx",
    "Name": "prd-db-cluster/AdminLoginInfo"
}

# シークレットのバージョン一覧を表示
$ aws secretsmanager list-secret-version-ids \
>   --secret-id prd-db-cluster/AdminLoginInfo
{
    "Versions": [
        {
            "VersionId": "c7264842-7f5d-407a-9b8e-24e63385e62a",
            "VersionStages": [
                "AWSCURRENT"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T09:50:12.998000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        },
        {
            "VersionId": "8db5d941-83e3-48bc-b63c-adcb714da48d",
            "VersionStages": [
                "AWSPREVIOUS"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T09:50:06.006000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        }
    ],
    "ARN": "arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx",
    "Name": "prd-db-cluster/AdminLoginInfo"
}

この状態で手動でローテーションをすると、マネージメントコンソール上ではローテーションのスケジュールが設定されたシークレット。と表示されます。

ローテーションのスケジュールが設定されたシークレット

シークレットをローテーションするLambda関数のCloudWatch Logsでは以下のようなログが出力されており、シークレットが正しくローテーションされていることを確認できます。

START RequestId: da9f8651-3e4f-41bd-9413-36a979df433f Version: $LATEST
[INFO]	2022-03-28T10:44:37.078Z	da9f8651-3e4f-41bd-9413-36a979df433f	Found credentials in environment variables.
[INFO]	2022-03-28T10:44:38.551Z	da9f8651-3e4f-41bd-9413-36a979df433f	createSecret: Successfully put secret for ARN arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx and version 7ba9c7e1-0531-4248-b37e-9b9073aa9fd3.
END RequestId: da9f8651-3e4f-41bd-9413-36a979df433f
REPORT RequestId: da9f8651-3e4f-41bd-9413-36a979df433f	Duration: 1772.00 ms	Billed Duration: 1772 ms	Memory Size: 128 MB	Max Memory Used: 73 MB	Init Duration: 426.19 ms	

START RequestId: 8e10fce2-5019-4d7e-90e0-cbd9eda8a99b Version: $LATEST
[INFO]	2022-03-28T10:44:39.192Z	8e10fce2-5019-4d7e-90e0-cbd9eda8a99b	setSecret: Successfully set password for user postgresAdmin in PostgreSQL DB for secret arn arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx.
END RequestId: 8e10fce2-5019-4d7e-90e0-cbd9eda8a99b
REPORT RequestId: 8e10fce2-5019-4d7e-90e0-cbd9eda8a99b	Duration: 618.21 ms	Billed Duration: 619 ms	Memory Size: 128 MB	Max Memory Used: 75 MB	

START RequestId: e2408615-4feb-4d8b-812c-286d8812a56f Version: $LATEST
[INFO]	2022-03-28T10:44:39.522Z	e2408615-4feb-4d8b-812c-286d8812a56f	testSecret: Successfully signed into PostgreSQL DB with AWSPENDING secret in arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx.
END RequestId: e2408615-4feb-4d8b-812c-286d8812a56f
REPORT RequestId: e2408615-4feb-4d8b-812c-286d8812a56f	Duration: 321.87 ms	Billed Duration: 322 ms	Memory Size: 128 MB	Max Memory Used: 75 MB	

START RequestId: cdd11f74-6b58-4564-94ef-3321862ab631 Version: $LATEST
[INFO]	2022-03-28T10:44:39.897Z	cdd11f74-6b58-4564-94ef-3321862ab631	finishSecret: Successfully set AWSCURRENT stage to version 7ba9c7e1-0531-4248-b37e-9b9073aa9fd3 for secret arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx.
END RequestId: cdd11f74-6b58-4564-94ef-3321862ab631
REPORT RequestId: cdd11f74-6b58-4564-94ef-3321862ab631	Duration: 355.55 ms	Billed Duration: 356 ms	Memory Size: 128 MB	Max Memory Used: 76 MB

対応方法は以上です。のんピでした!

と締めたいところではありますが、上述の「AWSPENDINGのラベルのバージョンを削除する」をしてはいけない場合もあります。

それは、以下のように「AWSPENDINGのラベルのバージョンにAWSCURRENTのラベルも付いている場合」です。

$ aws secretsmanager list-secret-version-ids \
   --secret-id prd-db-cluster/AdminLoginInfo
{
    "Versions": [
        {
            "VersionId": "11c46614-f0fb-4695-9fd9-7792cac5aa32",
            "VersionStages": [
                "AWSPREVIOUS"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T04:13:43.587000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        },
        {
            "VersionId": "4bcc57ad-6901-489f-88cf-c5b56f14cbca",
            "VersionStages": [
                "AWSCURRENT",
                "AWSPENDING"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T05:33:52.125000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        }
    ],
    "ARN": "arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx",
    "Name": "prd-db-cluster/AdminLoginInfo"
}

この状態だと、DBに新しいバージョンのシークレットが反映されているのかどうか判断できません。

そのため、このような場合はAWSPENDINGAWSCURRENTのラベルが付与されているバージョンのシークレットでDBに接続できるかどうかをまず確認します。

AWSPENDINGAWSCURRENTのラベルが付与されているバージョンのシークレットでDBに接続できないことを確認できた場合は、続けてAWSPREVIOUSのラベルが付与されているバージョンのシークレットでDBに接続できるかを確認します。

AWSPREVIOUSのラベルが付与されているバージョンのシークレットでDBに接続できる場合、DBには新しいバージョンのシークレットは反映されてなかったと判断できます。

そのため、前のバージョンを示すAWSPREVIOUSのラベルが付いているバージョンをデフォルトのバージョン(AWSCURRENT)となるようにラベルの貼り替えを行います。

ラベルの貼り替えも以下のようにAWS CLIでupdate-secret-version-stageを実行して行います。

# ラベルの貼り替え
$ aws secretsmanager update-secret-version-stage \
  --secret-id prd-db-cluster/AdminLoginInfo \
  --version-stage AWSCURRENT \
  --remove-from-version-id 4bcc57ad-6901-489f-88cf-c5b56f14cbca \
  --move-to-version-id 11c46614-f0fb-4695-9fd9-7792cac5aa32
{
    "ARN": "arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx",
    "Name": "prd-db-cluster/AdminLoginInfo"
}

# シークレットのバージョン一覧を表示
$ aws secretsmanager list-secret-version-ids \
   --secret-id prd-db-cluster/AdminLoginInfo
{
    "Versions": [
        {
            "VersionId": "11c46614-f0fb-4695-9fd9-7792cac5aa32",
            "VersionStages": [
                "AWSCURRENT"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T04:13:43.587000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        },
        {
            "VersionId": "4bcc57ad-6901-489f-88cf-c5b56f14cbca",
            "VersionStages": [
                "AWSPREVIOUS"
            ],
            "LastAccessedDate": "2022-03-28T00:00:00+00:00",
            "CreatedDate": "2022-03-28T05:33:52.125000+00:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        }
    ],
    "ARN": "arn:aws:secretsmanager:us-east-1:<AWSアカウントID>:secret:prd-db-cluster/AdminLoginInfo-vXO5yx",
    "Name": "prd-db-cluster/AdminLoginInfo"
}

これでローテーションできる状態になりました。

もし、AWSPENDINGAWSCURRENTのラベルが付与されているバージョンのシークレットでDBに接続できた場合は、ローテーションは正常に行えているが、ラベルの貼り替えが正常に行われていない状態なので、AWSPENDINGのラベルのみを削除します。その際のコマンドは以下の通りです。

$ aws secretsmanager update-secret-version-stage \
  --secret-id <シークレット名> \
  --version-stage AWSPENDING \
  --remove-from-version-id <AWSPENDING と AWSCURRENTのラベルが付いているバージョンのID>

AWS Secrets Managerのローテーションの仕組みを理解することが重要

AWS Secrets Managerでシークレットが正常にローテーションできなかった時の対応方法を紹介しました。

見慣れないエラーが出ても、AWS Secrets Managerのローテーションの仕組みを理解し、落ち着いてポイントを確認すれば対処できます。

そのためには自分の手で触ってみることが一番の近道だと感じました。

また、今回登場したラベルの操作は以下記事が参考になります。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!