[CFn]AWS Secrets Managerを利用してAmazon Redshiftのパスワードをローテーション管理する
表題について
こんにちわ!
DevelopersIO BASECAMP参加者の加藤です!
先日、昨年末のRDSとSecrets Managerの統合を受けて以下のような記事をUPしました。
RDSでは統合による新しいプロパティで直感的に設定が可能になり、コストも抑えられるようになった訳ですが、この記事を書いている2023年3月22日時点ではRedshiftは同様の統合の発表はない為、RDSでもこれ以前主流で利用されていた「Transform: AWS::SecretsManager-2020-07-23」を使用した記述が必要となります。
公式ドキュメントでも以下のように紹介がありました。
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