機密管理サービス AWS Secrets Manager で RDS のパスワードローテーションを試す

先日のAWS Summit 2018 San Francisco では、新しいサービス/機能が多数発表されました。その中でも、認証情報などの機密情報を管理する AWS Secrets Manager は非常に注目度が高いようです。Secrets Managerを使って、RDSのパスワードを管理・ローテーションを試してみましたので紹介します。
2018.04.06

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、菊池です。

先日のAWS Summit 2018 San Francisco では、新しいサービス/機能が多数発表されました。

その中でも、認証情報などの機密情報を管理する AWS Secrets Manager は非常に注目度が高いようです。

【完全新機能】DB認証情報やOAuthキーを一元管理可能なAWS Secrets Managerが発表されました!

この、Secrets Managerを使って、RDSのパスワードを管理・ローテーションを試してみましたので紹介します。

Secrets Manager のRDSパスワードローテーション

前提

実際にやってみてわかったことですが、RDSのパスワード変更はVPC内に起動するLambdaによって実行されます。LambdaがSecret Managerへのパスワード取得・変更と、RDSへの接続・パスワード変更を実行しますので、環境の前提として以下のような条件があります。

  • NAT Gatewayを配置し、Lambdaがパブリックリソース(Secret Managerへのエンドポイント)へのアクセスが可能
  • RDSでLambdaからの接続を許可するよう、Security Groupを設定

この条件をみたせていないと、ローテーションの処理に失敗します。動作イメージは以下のようになります。

検証の際は、管理対象のRDSの他に、NAT Gatewayなどもあらかじめ作成しておくようにしましょう。

やってみる

それでは実際に試してみます。Secrets Managerのコンソール画面に入りましょう。なんと、サービス開始時点から日本語に対応したコンソールです

[新しいシークレットの保存]に進みます。シークレットタイプは、[RDSデータベースの認証情報]を選び、対象のユーザ/パスワードを入力します。今回はマスターユーザを使いました。暗号化はデフォルトのまま。

対象のRDSインスタンスを選択して、次へ。

シークレットの名前を設定して、次へ。

自動ローテーションを設定します。[自動ローテーションを有効化]を選択し、間隔を選びます。また、ローテーションを実行するためのシークレットを選択します。これは、ローテーションのためにRDSにログインするための認証情報です。今回は、マスターユーザなので[ステップ1で指定したシークレット]を選択します。別のシークレットも利用できますが、管理対象のRDSでローテーション(パスワード変更)の権限があるユーザのシークレットである必要があります。

最後に、確認して保存します。

ここで、アプリケーションに組み込むためのサンプルコードも取得できます。(後からでも参照できます)

できました。保存時に、初回のローテーションが実行されます。しばらくして問題なければ、下図のように正常に保存された旨が表示されます。

この時、実際の処理としてはCloudFormationでServerlessアプリケーションがデプロイされ、Lambda関数とIAMロールが作成されています。

Lambdaのコンソールをのぞいてみると、Lambda関数が作成・実行されていることがわかります。

パスワードを取得してみる

それでは、AWS CLIを使って、Secrets ManagerからRDSのパスワードを取得、接続してみます。

まずはAWS CLIを最新にして、MySQLクライアントをインストールします。

$ sudo pip install -U awscli
$ sudo yum -y install mysql

AWS CLIでsecretsmanager get-secret-valueでシークレットを取得できます。

$ aws secretsmanager get-secret-value \
>     --secret-id arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:test/testApp/suser-WbKgTG \
>     --region ap-northeast-1
{
    "Name": "test/testApp/suser",
    "VersionId": "9a47007e-061a-44ff-b3cb-xxxxxxxxxxxx",
    "SecretString": "{\"username\": \"master\", \"engine\": \"mysql\", \"dbname\": \"test\", \"host\": \"test.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com\", \"password\": \"e2T2Vl3.bNP5g|q]0O1rHo~9kqb4ZEa]\", \"port\": 3306, \"dbInstanceIdentifier\": \"test\"}",
    "VersionStages": [
        "AWSCURRENT",
        "AWSPENDING"
    ],
    "CreatedDate": 1522995744.103,
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:test/testApp/suser-WbKgTG"
}

SecretStringに、username、dbname、host、passwordなど必要な情報が入っていますので、うまくパースして使うとよいでしょう。パスワードはe2T2Vl3.bNP5g|q]0O1rHo~9kqb4ZEa]です。

一度コンソールに戻り、ローテーションを実行してみます。

再度、コマンドでシークレットを取得してみます。

$ aws secretsmanager get-secret-value \
>   --secret-id arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:test/testApp/suser-WbKgTG \
>   --region ap-northeast-1
{
    "Name": "test/testApp/suser",
    "VersionId": "040e3bca-c234-4db0-a313-xxxxxxxxxxxx",
    "SecretString": "{\"username\": \"master\", \"engine\": \"mysql\", \"port\": 3306, \"host\": \"test.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com\", \"password\": \"!1)81T~c7>Geh-9xC;8Y&f2Th|ORR+&d\", \"dbname\": \"test\", \"dbInstanceIdentifier\": \"test\"}",
    "VersionStages": [
        "AWSCURRENT",
        "AWSPENDING"
    ],
    "CreatedDate": 1523006698.473,
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:test/testApp/suser-WbKgTG"
}

パスワードが!1)81T~c7>Geh-9xC;8Y&f2Th|ORR+&dに変更されていることが確認できます。これでMySQLにログインして、ちゃんと接続できることが確認できました。

まとめ

新しいサービス、AWS Secrets Managerの、シークレットの作成、ローテーションを検証しました。

VPC Lambdaの実行環境で少しハマりましたが、うまく利用することでパスワード管理を楽に運用することができそうです。