🗝️

[CFn]AWS Secrets Managerを利用してAmazon Redshiftのパスワードをローテーション管理する

2023/03/22に公開

表題について

こんにちわ!

DevelopersIO BASECAMP参加者の加藤です!

先日、昨年末のRDSとSecrets Managerの統合を受けて以下のような記事をUPしました。
https://zenn.dev/devcamp/articles/54ffd860025f64


RDSでは統合による新しいプロパティで直感的に設定が可能になり、コストも抑えられるようになった訳ですが、この記事を書いている2023年3月22日時点ではRedshiftは同様の統合の発表はない為、RDSでもこれ以前主流で利用されていた「Transform: AWS::SecretsManager-2020-07-23」を使用した記述が必要となります。


公式ドキュメントでも以下のように紹介がありました。
https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/cfn-example_Redshift-secret.html

RDSで同様の設定をされた経験のある方にとっては横移動で目新しい情報は存在しないのですが、念の為設定してみたいと思います。

テンプレの説明

公式ドキュメントにサンプルがありましたので、引用の上補足のコメントだけ付け加えたものが以下になります。

公式ドキュメントまま引用
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::SecretsManager-2020-07-23 #必須

Resources:

  TestVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      
  TestSubnet01:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.96.0/19
      AvailabilityZone:
        Fn::Select:
        - '0'
        - Fn::GetAZs:
            Ref: AWS::Region
      VpcId:
        Ref: TestVPC
	
  TestSubnet02:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.128.0/19
      AvailabilityZone:
        Fn::Select:
        - '1'
        - Fn::GetAZs:
            Ref: AWS::Region
      VpcId:
        Ref: TestVPC
	
  SecretsManagerVPCEndpoint: #RedshiftのあるVPCにローテーション用Lambda関数が置かれる為、関数がVPC外のSecretsManagerと疎通する為に必要
    Type: AWS::EC2::VPCEndpoint
    Properties:
      SubnetIds:
      - Ref: TestSubnet01
      - Ref: TestSubnet02
      SecurityGroupIds:
      - Fn::GetAtt:
        - TestVPC
        - DefaultSecurityGroup
      VpcEndpointType: Interface
      ServiceName:
        Fn::Sub: com.amazonaws.${AWS::Region}.secretsmanager
      PrivateDnsEnabled: true
      VpcId:
        Ref: TestVPC
	
  MyRedshiftSecret: #今回作成されるシークレット
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: This is my rds instance secret
      GenerateSecretString:
        SecretStringTemplate: '{"username": "admin"}'  #usernameというKeyのValueはadminにしてねという部分
        GenerateStringKey: password #KeyはPasswordで
        PasswordLength: 16 #Valueの長さは16文字でシークレットを作成してねというという部分
        ExcludeCharacters: "\"@/\\"
      Tags:
      - Key: AppName
        Value: MyApp
	
  MyRedshiftCluster:
    Type: AWS::Redshift::Cluster
    Properties:
      DBName: myyamldb
      NodeType: ds2.xlarge
      ClusterType: single-node
      ClusterSubnetGroupName:
        Ref: ResdshiftSubnetGroup
      MasterUsername:
        Fn::Sub: "{{resolve:secretsmanager:${MyRedshiftSecret}::username}}" #ここでusernameというKeyからValueであるadminを呼び出している
      MasterUserPassword:
        Fn::Sub: "{{resolve:secretsmanager:${MyRedshiftSecret}::password}}" #ここでpasswordというKeyからValueである生成されたシークレットストリングを呼び出している
      PubliclyAccessible: false
      VpcSecurityGroupIds:
      - Fn::GetAtt:
        - TestVPC
        - DefaultSecurityGroup
	
  ResdshiftSubnetGroup:
    Type: AWS::Redshift::ClusterSubnetGroup
    Properties:
      Description: Test Group
      SubnetIds:
      - Ref: TestSubnet01
      - Ref: TestSubnet02
      
  SecretRedshiftAttachment: #クラスターとシークレットの紐付け
    Type: AWS::SecretsManager::SecretTargetAttachment
    Properties:
      SecretId:
        Ref: MyRedshiftSecret
      TargetId:
        Ref: MyRedshiftCluster
      TargetType: AWS::Redshift::Cluster #ここはRDSの時AWS::RDS::DBClusterやAWS::RDS::DBInstanceだった所
      
  MySecretRotationSchedule: シークレットのローテーションスケジュール
    Type: AWS::SecretsManager::RotationSchedule
    DependsOn: SecretRedshiftAttachment
    Properties:
      SecretId:
        Ref: MyRedshiftSecret
      HostedRotationLambda:
        RotationType: RedshiftSingleUser #RDSの時はMySQLやPostgress、OracleなどのSingleUser or MultiUserだった箇所
        RotationLambdaName: SecretsManagerRotationRedshift
        VpcSecurityGroupIds:
          Fn::GetAtt:
          - TestVPC
          - DefaultSecurityGroup
        VpcSubnetIds: # ネストスタック内で作成される関数が設置されるサブネット=Redshiftが配置されているサブネット
          Fn::Join:
          - ","
          - - Ref: TestSubnet01
            - Ref: TestSubnet02
      RotationRules: #
        Duration: 2h
        ScheduleExpression: 'cron(0 8 1 * ? *)'

※最下部のRotationRules:についてこちら

図にすると

以下のようになります。

要点説明

テンプレート実行前〜実行中

以下のようにコンソール画面では実行手前に確認用のチェックボックスボックスが出ますのでチェックします。


テンプレートの実行を行うと、以下のように最初にTransform句(Transform: AWS::SecretsManager-2020-07-23)による結果(Succeeded)が表示されます。


ネストされたスタックが作成され、


中身は以下のようになっています。

しばらく待つとスタックも無事作成完了したようです。


スタック作成完了後

SecretsManagerコンソールで実際に確認してみます。


passwordが確り作成されています。

私はRotationRules:にAutomaticallyAfterDays:30を指定したのですが、指定したローテーション間隔も無事反映されています。


SecretsManagerコンソールからローテーションさせてみます。






値を確認してみると

先程確認した際と違う値が生成されている事が確認出来ました。

最後に

RedshiftでもSecretsManagerと統合が発表される事を祈っています。

お付き合いいただき有難うございました。

デベキャン

Discussion