概要
最近AWS CDKで環境構築する機会がありました。
その際に既存のS3バケットをCDKの管理下におく方法を調査したので共有させていただきます。
なお、今回はcdk import
を使用して既存リソースをインポートしていきます。
準備
まず、CDKのプロジェクトを作成します。
mkdir cdk-import-bucket && cd cdk-import-bucket
cdk init sample-app -l typescript
lib/cdk-import-bucket-stack.ts
を確認すると、SNS
やSQS
のリソースを作成する記述があるので削除しておきます。
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkImportBucketStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
}
}
一度この状態でデプロイしてAWS上にCloudFormationのスタックを作成しておきます。
cdk deploy
次に、CDKでインポートするS3バケットを作成します。
手動で作成してもいいですが、今回はCloudFormationで作成してみます。
# sample-bucket.yaml
AWSTemplateFormatVersion: 2010-09-09
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: sample-bucket-qwer
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced
デプロイ
aws cloudformation deploy --template-file sample-bucket.yaml --stack-name sample-bucket-stack
これでCDKで管理していないS3バケットの作成ができました。
cdk import
してみる
では、上記で作成したS3バケットをCDKの管理下にインポートしていきます。
まず、lib/cdk-import-bucket-stack.ts
を下記のように変更してS3バケットの定義を追加します。
import { Stack, StackProps } from 'aws-cdk-lib';
import { Bucket } from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
export class CdkImportBucketStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
new Bucket(this, 'ImportBucket', {})
}
}
差分を確認してみます。
cdk diff
Stack CdkImportBucketStack
Resources
[+] AWS::S3::Bucket ImportBucket ImportBucketBAF3A8E9
✨ Number of stacks with differences: 1
新しくS3バケットが作成されようとしているのがわかります。
ではここで定義したS3バケットに対し、cdk import
で既存のリソースをインポートしてみます。
cdk import
CdkImportBucketStack
CdkImportBucketStack/ImportBucket/Resource (AWS::S3::Bucket): enter BucketName [undefined]:
上記のようにインポートするバケット名を聞かれるので入力します。
すると失敗してしまいます。
これは、対象のS3バケットを作成したときにCloudFormationで作成したことが原因です。
すでにCloudFormationで管理されているリソースについてはcdk import
ができないようです。
なのでS3を作成したCloudFormationスタックを削除しましょう。
削除前にDeletionPolicy
を修正して、スタックを削除してもS3バケットが削除されないようにします。
AWSTemplateFormatVersion: 2010-09-09
Resources:
S3Bucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain # 追加
Properties:
BucketName: sample-bucket-qwer
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced
DeletionPolicy
を更新するためにデプロイ
aws cloudformation deploy --template-file sample-bucket.yaml --stack-name sample-bucket-stack
上記が成功したのちスタックの削除
aws cloudformation delete-stack --stack-name sample-bucket-stack
これでCloudFormationのスタックで管理されていないS3バケットが残りました。
もう一度cdk import
してみます。
cdk import
CdkImportBucketStack
CdkImportBucketStack/ImportBucket/Resource (AWS::S3::Bucket): enter BucketName [undefined]: sample-bucket-qwer
CdkImportBucketStack: importing resources into stack...
CdkImportBucketStack: creating CloudFormation changeset...
✅ CdkImportBucketStack
Import operation complete. We recommend you run a drift detection operation to confirm your CDK app resource definitions are up-to-date. Read more here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/detect-drift-stack.html
成功しました!
マネージメントコンソールでスタックのステータスを確認するとIMPORT_COMPLETE
になっています。
うまくいったようですが、cdk import
を行った際の出力に気になるメッセージがありました。
We recommend you run a drift detection operation to confirm your CDK app resource definitions are up-to-date. Read more here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/detect-drift-stack.html
「ドリフトの検出するのをお勧めするよ」と言われてます。
ドリフトとはこちらに書かれている通りなのですが、要はCloudFormationのスタックに定義されている構成と、実際のリソースの構成に差異がないかを検出するために使用されるものです。
なのでCloudFormationで管理しているリソースのプロパティを手動で変更した場合などの検出に使用できます。
今回で言うとCDKにインポートした定義と既存リソースの構成に差異がないかチェックしてねということのようです。
メッセージのURLにドリフト検出の方法が載っているのでそれ通りに進めたところ、ドリフトステータスがIN_SYNC
(差分なし)となることを確認しました。
なので正常にインポートが完了したことになります。
プロパティの更新を試す
リソースのインポートができたので、試しにS3バケットのプロパティの更新も試してみます。
ライフサイクルルールを追加してみましょう。
import { Duration, Stack, StackProps } from 'aws-cdk-lib';
import { Bucket } from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
export class CdkImportBucketStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
new Bucket(this, 'ImportBucket', {
lifecycleRules: [
{
id: "DeleteExpiredData",
enabled: true,
expiration: Duration.days(30),
}
]
})
}
}
差分の確認
cdk diff
Stack CdkImportBucketStack
Resources
[~] AWS::S3::Bucket ImportBucket ImportBucketBAF3A8E9
└─ [+] LifecycleConfiguration
└─ {"Rules":[{"ExpirationInDays":30,"Id":"DeleteExpiredData","Status":"Enabled"}]}
✨ Number of stacks with differences: 1
想定した差分が確認できたのでデプロイ
cdk deploy
ライフサイクルルールが設定されたか確認してみます
aws s3api get-bucket-lifecycle-configuration --bucket sample-bucket-qwer
{
"Rules": [
{
"Expiration": {
"Days": 30
},
"ID": "DeleteExpiredData",
"Filter": {
"Prefix": ""
},
"Status": "Enabled"
}
]
}
うまくいきました!
出力されたCloudFormationテンプレートでもプロパティが追加されていることを確認できます。
cdk.out > CdkImportBucketStack.template.json
{
"Resources": {
"ImportBucketBAF3A8E9": {
"Type": "AWS::S3::Bucket",
"Properties": {
"LifecycleConfiguration": {
"Rules": [
{
"ExpirationInDays": 30,
"Id": "DeleteExpiredData",
"Status": "Enabled"
}
]
}
},
}
まとめ
CDKで既存のS3バケットをインポートする方法を紹介しました。
今回インポートの対象としたのはS3バケットでしたが、他のリソースでも同じような手順で実行できるのではないかと思います。
どなたかの参考になれば幸いです。