AWS Secrets ManagerでAmazon RDSのパスワードローテーションを行うためのCloudFormationテンプレートを試してみる

2022.02.25

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

Introduction:

多くのアプリケーションでは、様々なユースケースでシークレットを使用しています。アプリケーションIDとシークレットキーを使ってトークンを生成したり、シークレットキーそのものを使ってAPIにアクセスしたり、ユーザー名とパスワードを使ってRDSからデータを取得するためのデータベース接続文字列を作ったりします。もしかしたら、あなたの組織で実施されている様々なセキュリティ測定や標準があるかもしれません。1つ確かなことは、パスワードを設定ファイルに保存したり、平文でハードコードしたりしないことです。これらの秘密/パスワードを安全な方法で保存し、取得することは困難な作業です。この投稿では、AWS Secret Managerを使用したより堅牢なソリューションについて説明するつもりです。

while using secret manager:

  • 動的なパラメータパターンです。 '{{resolve:ssm:parameter-name:version}}', 正確なバージョンを指定する必要があります。
  • Secrets ManagerとCloudFormationのどちらも、解決されたシークレット値をログに記録したり、永続化したりしない。
  • Secrets Managerでシークレットを更新しても、CloudFormationのシークレットは自動的に更新されない
  • テンプレートで秘密の更新を管理するには、version-idを使用して秘密のバージョンを指定することを検討してください。 {{resolve:secretsmanager:secret-id:secret- string:json-key:version-stage:version-id}} と指定します。

HANDS ON:

1. AWS::SecretsManager::Secretを作成します。
  - GenerateSecretStringを指定し、シークレットをランダムに生成します。
2. その秘密を参照するAWS::RDS::DBInstanceを作成します。
- 動的参照を使用する
3. AWS::SecretsManager ::SecretTargetAttachmentを作成する。
- Secrets ManagerのシークレットとRDSのデータベースを一緒にリンクさせる
- シークレットマネージャーのJSONにRDSのプロパティを追加します。
4. AWS::SecretsManager::RtationSchedule を作成します。
- Lambda関数が作成されます
- シークレットアタッチメントを作成した後に行う必要があります

Template with explanation:

AWSTemplateFormatVersion: 2010-09-09
# 回転に必要な
Transform: AWS::SecretsManager-2020-07-23
Description: "Secrets Manager with automatic rotation"


Resources: 
  # SecretString JSON にランダムで生成されるパスワードを持つSecretリソースです。
  MyRDSSecret:
    Type: "AWS::SecretsManager::Secret"
    Properties:
      Description: "This is automatic generated Secrets Manager secret for an RDS DB instance"
      GenerateSecretString:
        # ユーザー名 "developersio"がハードコードされている
        SecretStringTemplate: '{"username": "admin"}'
        # パスワード "キーが生成され、マージされます。
        GenerateStringKey: "password"
        PasswordLength: 16
        ExcludeCharacters: '"@/\'

#RDSインスタンスリソースです。マスターユーザー名とパスワードは、シークレットマネージャーから値を解決するために動的参照を使用します。
#動的参照は、CloudFormationが解決された値をログに残したり、持続させたりしないことを保証しています。
#秘密名はCloudFormationによって生成されるので、
#秘密リソースの論理IDへのRefを使用して動的参照を構築しています。
  MyRDSInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: 20
      DBInstanceClass: db.t2.micro
      Engine: mysql
      MasterUsername: !Join ['', ['{{resolve:secretsmanager:', !Ref MyRDSSecret, ':SecretString:username}}' ]]
      MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref MyRDSSecret, ':SecretString:password}}' ]]
      BackupRetentionPeriod: 0
      DBInstanceIdentifier: 'rotation-instance'

#これはSecretTargetAttachmentリソースで、参照されているRDSインスタンスに関するプロパティで、
#参照されているSecretリソースを更新します。
  SecretRDSInstanceAttachment:
    Type: "AWS::SecretsManager::SecretTargetAttachment"
    Properties:
      SecretId: !Ref MyRDSSecret
      TargetId: !Ref MyRDSInstance
      TargetType: AWS::RDS::DBInstance


#これはRotationScheduleリソースです。
#リソース作成時に最初のローテーションが行われ、
#その後のローテーションはローテーションルールに従ってスケジュールされます
# ローテーションが成功するために必要なすべての情報を含む秘密を確保するために、
#作成される SecretTargetAttachmentリソースに明示的に依存します。
  MySecretRotationSchedule:
    Type: AWS::SecretsManager::RotationSchedule
    Properties:
      SecretId: !Ref MyRDSSecret
      # AWSが提供するLambda関数を利用する
      HostedRotationLambda:
        RotationLambdaName: SecretsManagerRotation
        RotationType: MySQLSingleUser
      RotationRules:
        AutomaticallyAfterDays: 30
    #秘密がRDSデータベースにリンクされる前に、秘密の回転を有効にすることができないので、重要な依存します。
    DependsOn: SecretRDSInstanceAttachment

 

Resources: