Aurora Serverless v2のPostgreSQL互換でRDS Data APIが使えるようになった。
最小ACUを0にできないなど、Serverless v1と完全互換ではないが、ちょうどSalesforceやHTTPでAPI連携できるRDBを使いたい要件があったので、検証することに。
Secrets Managerへの認証情報の登録など、RDS Data APIを使うには準備が必要だが、AWS CDKで環境構築すると自動でやってくれたのでメモ。
環境
AWS CDK Toolkit v2.133.0、AWS CLI v2.15.30。
AWS CDKプロジェクトの初期化
AWS CDKのインストール等は省略。以下のコマンドでプロジェクトを初期化。
mkdir -p aurora-serverless-example/backend cd aurora-serverless-example/backend cdk init app --language typescript git add package-lock.json git commit -m 'add package-lock.json'
Stackの記述
作成された aurora-serverless-example/backend/lib/backend-stack.ts
に以下を記述。
import { Stack, StackProps } from 'aws-cdk-lib' import { IpAddresses, SubnetType, Vpc } from 'aws-cdk-lib/aws-ec2' import { AccessKey, User } from 'aws-cdk-lib/aws-iam' import { AuroraPostgresEngineVersion, ClusterInstance, DatabaseCluster, DatabaseClusterEngine, } from 'aws-cdk-lib/aws-rds' import { StringParameter } from 'aws-cdk-lib/aws-ssm' import { Construct } from 'constructs' export class BackendStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props) // VPC const vpc = new Vpc(this, 'Vpc', { vpcName: 'AuroraServerlessExample', ipAddresses: IpAddresses.cidr('172.30.0.0/16'), maxAzs: 2, subnetConfiguration: [ { cidrMask: 24, subnetType: SubnetType.PRIVATE_ISOLATED, name: 'PrivateIsolated', }, ], }) // RDS const databaseCluster = new DatabaseCluster(this, 'Aurora', { engine: DatabaseClusterEngine.auroraPostgres({ version: AuroraPostgresEngineVersion.VER_15_5, }), serverlessV2MinCapacity: 0.5, serverlessV2MaxCapacity: 1, writer: ClusterInstance.serverlessV2('writer'), readers: undefined, enableDataApi: true, iamAuthentication: true, storageEncrypted: true, defaultDatabaseName: 'aurora_serverless_example', vpc, vpcSubnets: vpc.selectSubnets({ subnetType: SubnetType.PRIVATE_ISOLATED, }), }) // IAM User const iamUser = new User(this, 'User') databaseCluster.grantDataApiAccess(iamUser) databaseCluster.secret?.grantRead(iamUser) // AccessKey const accessKey = new AccessKey(this, 'AccessKey', { user: iamUser, }) const ssmAccessKeyId = 'AccessKeyId' new StringParameter(this, ssmAccessKeyId, { parameterName: ssmAccessKeyId, stringValue: accessKey.accessKeyId, }) const ssmSecretAccessKey = 'SecretAccessKey' new StringParameter(this, ssmSecretAccessKey, { parameterName: ssmSecretAccessKey, stringValue: accessKey.secretAccessKey.unsafeUnwrap(), }) } }
検証用なのでいろいろ適当だが、以下解説。
VPCの作成
RDS Data APIはエンドポイント経由で実行するためか、サブネットタイプは PRIVATE_ISOLATED
でよかった。
AZは2以上指定しないと、DatabaseCluster生成時にエラーが発生するため、最小値の2としている。(東京リージョンで subnetConfiguration
に1種類しか指定しない場合、 maxAzs
を指定しなくてもAZは2つになる模様)
DatabaseClusterの作成
検証のため、ACUはMin/Maxそれぞれ最小値にし、リーダーインスタンスは未設定。なお、RDS Data APIは実行するSQLの種類によらず、ライターインスタンス経由で実行される模様。
enableDataApi
に true
を指定すると、RDS Data APIが有効となる。また、上記リンクやこちらにあるように、RDS Data APIの実行にはSecrets Managerにデータベース側のユーザーの認証情報が必要だが、CDKを使うと DatabaseCluster
の第3引数の credentials
で指定した認証情報が、自動的にSecrets Managerに保存される。
上記のコードでは credentials
を省略しているため、ユーザー名はデフォルトの postgres
となる。別のユーザー名を指定したい場合、以下のように記述可能。
import { Credentials } from 'aws-cdk-lib/aws-rds' new DatabaseCluster(this, 'Aurora', { credentials: Credentials.fromGeneratedSecret('userName'), }
iamAuthentication
にも true
を指定しているが、これはIAM データベース認証を有効化するかのプロパティ。RDS Data APIの実行時には、Signature Version 4による署名が必須なので、IAMユーザーが必要となる。
IAMユーザーの作成
RDS Data APIの実行に必要な権限を持ったIAMユーザーを作成する。検証なので、直接IAMユーザーに権限追加している。
AWS 管理ポリシー AmazonRDSDataFullAccess には、Data API のアクセス許可が含まれています。
との記載があるが、以下のように AmazonRDSDataFullAccess
ポリシーを付与しても、RDS Data API実行時にSecrets Managerの読み取り権限なしでエラーとなる。
new User(this, 'User', { managedPolicies: [ ManagedPolicy.fromAwsManagedPolicyName('AmazonRDSDataFullAccess'), ], })
原因は、 AmazonRDSDataFullAccess
内で読み取り可能なシークレットのARNが arn:aws:secretsmanager:*:*:secret:rds-db-credentials/*
に限定されているため。DatabaseClusterのcredentialsから作成されたシークレットのARNは、 arn:aws:secretsmanager:*:*:secret:<DatabaseClusterのID>Secret<ランダム文字列8桁>
となるため、一致しない。
credentialsから作成されたシークレットは databaseCluster.secret
で参照可能なので、 databaseCluster.grantDataApiAccess(iamUser)
でDBクラスターへのRDS Data API実行権限、 databaseCluster.secret?.grantRead(iamUser)
でシークレットの読み取り権限をそれぞれIAMユーザーに追加した。
アクセスキーの作成
AWS Signature Version 4で使用するアクセスキーを作成し、AccessKeyIdとSecretAccessKeyをそれぞれ保存する。
SecretAccessKeyはSecrets Managerに保存したほうがいいのだろうが、検証なのでAccessKeyIdと同じくSystems Managerに保存している。
デプロイ
AWS CLIでログインし、 cdk synth
および cdk deploy
でデプロイ。東京リージョンへのデプロイの場合、15分弱で完了した。
動作確認
RDSのクエリエディタはRDS Data APIを用いてSQLを実行するため、クエリエディタを用いることで動作確認可能(IAMにRDS Data APIの実行権限およびシークレットの参照権限がある前提)。
cdk.out/BackendStack.template.json
を参照するかSecrets Managerを管理コンソールで開くなどして、作成されたシークレットのARNを確認しておく。
AWSの管理コンソールからRDSを開き、左フレームの「クエリエディタ」をクリック。以下の手順でクエリエディタを起動。
- 作成したDBクラスターを選択
- 「データベースユーザー名」で「Secrets Manager ARN と接続する」を選択
- 「Secrets manager ARN」に、確認したシークレットのARNを設定
- 「データベースの名前を入力」に、DB名を設定。今回は
aurora_serverless_example
。
以下のSQLで、DDLおよびDMLが実行できることを確認する。
CREATE SCHEMA example; CREATE TABLE example.users ( user_id BIGSERIAL NOT NULL, user_name VARCHAR(50) NOT NULL, PRIMARY KEY (user_id) ); INSERT INTO example.users (user_name) VALUES ('user1'); INSERT INTO example.users (user_name) VALUES ('user2'); INSERT INTO example.users (user_name) VALUES ('user3'); SELECT user_id, user_name FROM example.users ORDER BY user_id;
なお、クエリエディタではステートメントごとに別リクエストで実行されるのか、 SET search_path TO example;
などを挟んでも効果がないため、それぞれスキーマを指定している。
振り返り
初CDKなので、これでいいのやら。ただ、シークレットを自動で設定してくれたりと、便利なのは間違いない。
昔CloudFormationを手書きしていたのに比べると、格段に楽になったなぁ。