3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

フリューAdvent Calendar 2022

Day 18

[AWS]CFnで作成したスタックをCDKで書き直し→デプロイ(&その逆)したらどうなるの

Last updated at Posted at 2022-12-17

こんにちは、AWSおよびCDKひよこクラブのmasaozi3です:hatching_chick:
本記事はAWS/CDK/CloudFormation初学者:hatching_chick:向けの内容です。

あまりやらないとおもうのでニーズがあるのかわかりませんが、一度CFnで作成したスタック定義を完全にCDKで書き直したい場面にぶちあたり、どういう挙動になるのか気になったので調査してみました。
そしてさらにニーズがあるのかわかりませんが、逆にCDKで作成したスタックをCFnに完全に書き換えるパターンもやってみました。

ちなみにCDKではcloudformation-include を使うことで、CFnファイルをテンプレートとして取り込みつつ実装することもできるそうですが、今回はCDKで全てを書き直し、CFnのファイルは破棄できる状態にすることが前提です。

スタックIDを一致させれば同一のスタックへの操作と認識してくれて、その中のリソースもIDを一致させれば同じリソースへの操作として認識してくれないかな…というのが期待する結果です。
「前述のライブラリがあるってことは、うまいこといけるのでは?」という甘い考えでやっていきます:relaxed:

検証環境

  • Mac OS 12
  • Typescript 4.8.4
  • node 18.10.0
  • CDK CLI 2.44.0

準備

S3と、SSL通信じゃないアクセスを弾くバケットポリシーを作成するだけのシンプルなスタックを定義します。
スタックID、リソースのIDがCFnとCDKで一致するように明記しています。

CFn

s3stack.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: create s3 bucket from CFn

Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: 'cfn-cdk-sample-bucket'
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  S3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: 'cfn-cdk-sample-bucket'
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action: 's3:*'
            Effect: Deny
            Principal: '*'
            Resource:
              - !GetAtt S3Bucket.Arn
              - !Sub ${S3Bucket.Arn}/*
            Condition:
              Bool:
                'aws:SecureTransport': 'false'

CDK

スタックの定義はこちら。

s3stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import {BlockPublicAccess, Bucket, BucketAccessControl} from "aws-cdk-lib/aws-s3";

export class s3Stack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    new Bucket(this, 'S3Bucket', {
      bucketName: 'cfn-cdk-sample-bucket',
      accessControl: BucketAccessControl.PRIVATE,
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
      enforceSSL: true
    })
  }
}

CDK appの方はこちら。

cfncdksample.ts
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { s3Stack } from '../lib/s3-stack';

const app = new cdk.App();

new s3Stack(app, 'cfn-cdk-sample-stack', {
    stackName: 'cfn-cdk-sample-stack',
    description: 'create s3 bucket from CDK yeah!',
});

調査1. CFn→CDKの書き換え

まずはCFnをデプロイします。

$ aws cloudformation create-stack \
--stack-name cfn-cdk-sample-stack \
--template-body file://path/to/s3stack.yaml \
--profile my-profile

AWSコンソール上で確認すると無事出来上がっています。
cfn-cdk-step1.png

次はいざ、このスタックに対してCDKでdiffを出してみます。

$ npm run cdk diff cfn-cdk-sample-stack -- --profile my-profile

いろいろ差分が示されました。
cfn-cdk-step2.png
ふむふむどうやら無事に、CFnで作成したスタックの更新と認識されているようです。
わざと変えておいたDescriptionや、実装ミスで完全に同じにできていない箇所、CFnとCDKでの書き方の違いによるものが変更内容として出ていますね。
ここまでは良さそうです。

スタック内のリソースはどうでしょうか。
cfn-cdk-step2-2.png
残念ながら、完全に別のリソースとして作り直されてしまうようです。
赤字のdestroyが悲しい…:weary:

特にS3はIDもバケット名も揃えて書きましたが、CDKによって指定したIDをもとに内部でさらにユニークなIDを振り直されてしまってだめなようです。
XXX.fromLookup()とかXXX.fromXXXArn()など既存のリソースを参照するための実装があることを思うと、納得の結果ではあります。

一応デプロイもしてみましょう。

$ npm run cdk deploy cfn-cdk-sample-stack -- --profile my-profile

更新失敗しました。
cdk-cfn-step3.png

cdk-cfn-step3-2.png
diffの段階で判明したとおり、別のリソースとして同じ名前のバケットを作成するという操作をしようとしたため
「同名のバケットもうこのスタック内にありますね」と怒られてしまったようです:skull:

CFn→CDKのまとめ

  • スタックはIDを揃えれば同一のスタックとして認識してくれる:relaxed:
  • スタック内のリソースは別物(作り直し)になる:frowning2:
    • newしてる限りCDKでIDが振り直される
    • XXX.fromLookup()とかXXX.fromXXXArn()など既存のリソースを参照するための実装がある

調査2. CDK→CFnの書き換え

先程のCFn→CDKで作成したスタックやリソースは一通り削除したうえで、まずはCDKをデプロイします。

$ npm run cdk deploy cfn-cdk-sample-stack --profile my-profile

ここで設定されたリソースのIDをもとに少しだけCFnを修正します。

s3stack.yaml
Resources:
  S3Bucket07682993:  # ここをCDKで設定されたIDに修正
    Type: AWS::S3::Bucket
    Properties:
      BucketName: 'cfn-cdk-sample-bucket'

〜中略〜

  S3BucketPolicyF560589A:  # ここをCDKで設定されたIDに修正
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: 'cfn-cdk-sample-bucket'
    

CFnではdiffを出す方法がないので、今回は変更セットを作成してみます。

$ aws cloudformation create-change-set \
--stack-name {stackArn}\
--change-set-name DemoChangeSet \
--template-body file://path/to/s3stack.yaml \
--profile my-profile

AWSコンソール上から、作成した変更セットを確認してみると、無事に変更セットが作成されていました。
cdk-cfn-step4-2.png
CDKで作成したスタックの更新と認識されているようです。

アクションの欄を見ると、S3もバケットポリシーも Modify とあるので、CDKで作成したリソースに対する更新だと認識してくれているようです :tada:
CDKMetadataは Remove とあるのでもう不要だと判断して削除されるようですね。

そして置換の欄を見ると、S3はFalseなので再作成されないようですね。CFn→CDKのときの挙動を思うと納得です。
バケットポリシーはTrueなので、同じIDで作成され直すようです。
このあたりについてはどのリソースタイプの何のプロパティを変更するかによって決定されるので今回の調査としては問題ないです。

変更セットを適用してみると、無事にバケットを作り直すことなくスタックの更新が完了しました。
cd-cfn-step5.png

CDK→CFnのまとめ

  • スタックはIDを揃えれば同一のスタックとして認識してくれる:relaxed:
  • スタック内のリソースはもIDを揃えれば同一のスタックとして認識してくれる:relaxed:

まとめ

ということで、今回はレアケースだと思いますがCFnで作成したスタックとリソースをCDKでもう一度書き直してみるとどうなるのか試してみました。

CFn→CDKのケースではIDを揃えればスタックは同じものを操作できますが、スタック内のリソースはCDKによってIDを振り直されるので別のものと認識されてしまう事がわかりました。
逆にCDK→CFnのケースでは、IDを揃えればスタックもリソースも同じものを操作できるということがわかりました。

CFn→CDKのケースで、リソースを作り直されたくなければちゃんとLookupせよ、ということで
ニーズのよくわからない調査はこれにて終了です!お疲れさまでした:xmas-wreath2:

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?