スタイル・エッジ技術ブログ

士業集客支援/コンサルティングのスタイル・エッジのエンジニアによるブログです。

CDKでCloudFormation StackSetsのデプロイを行ってみる

はじめに

お世話になっております。システム事業部のONです。
前回の執筆からちょうど2年になります。

中途入社して1カ月でアドベントカレンダー書いてと言われ、2~3カ月で技術ブログを書いてと言われ...
どちらもネタがないとオロオロしながら書いた記憶が鮮明に残っています。
そんな今回もネタがなくオロオロしているので試したかったことを実践してみます。

課題発生

ここ半年程、CloudFormationやSAM, CDKを触ることが多くありました。
これらの沼は深く、私はまだまだくるぶしぐらいしか浸かれていない状況です。

そんな最中、同一AWSアカウントの全リージョンにデプロイする内々のCDKを作る必要が発生しました。
当時はリージョンの配列をループさせて、各リージョンにスタックを作成する形で実装を終えたのですが...
後からCloudFormation StackSetsの存在を思い出し、これを利用すればもっとスマートな形にできたのでは...と疑問が出てきました。

StackSetsとCDK

CloudFormation StackSetsは複数のAWSアカウントやリージョンにスタックを作成できるサービスです。
すなわち、1つのテンプレートで複数のAWSアカウントやリージョンへの一括デプロイをしてくれます。
ドキュメントはこちらから。

StackSets の概念 - AWS CloudFormation https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/stacksets-concepts.html#stacksets-concepts-stackset

AWS Organizationsと組み合わせると、特定のOUに対してデプロイできたりメンバーアカウントが増えた際に自動的に反映してくれたりする、より強力な存在となってくれます。

CDKもAWSの各種リソースをデプロイすることができる仕組みです。
内部的にはCloudFormationが動いていますが、各種言語で定義できることが魅力の一つです。
CDKに関しては、当ブログで紹介している記事があるのでよかったらご参照ください!

AWS CDK入門|準備からサブネットを分けるまで - スタイル・エッジ・グループ技術ブログ https://techblog.styleedge.co.jp/entry/2022/07/19/163825

さて、CDKで定義したリソースを複数のAWSアカウントやリージョンにデプロイするためにStackSetsと連携することはできるのか?というお話ですが...
CDKとStacksetsの連携は残念ながらサポートはされておらず、長い間issueがopenしている状態です。

StackSets Support · Issue #66 · aws/aws-cdk-rfcs · GitHub
https://github.com/aws/aws-cdk-rfcs/issues/66

ただ、このissueのなかでCDKを使ってStackSetsを作成する方法を紹介している方がいらっしゃいました。

https://github.com/aws/aws-cdk-rfcs/issues/66#issuecomment-754599325

せっかくなので、試してみましょう!!

実践編

StackSetsを扱うための準備として、下記2つのIAMロールを作成します。

AWSCloudFormationStackSetExecutionRole
操作するAWSアカウントのAdministratorAccessポリシーを利用できるロール

AWSCloudFormationStackSetAdministrationRole
CloudFormation経由でAWSCloudFormationStackSetExecutionRoleを利用できるロール

作成手順は以下のドキュメントをご参照ください。

Grant self-managed permissions - AWS CloudFormation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs-self-managed.html

これらのIAMロールを作成するにあたって「ドキュメントは分割記載されていて分かり辛い!」という方は、CloudFormationのテンプレートも用意されていますのでおすすめです。

https://s3.amazonaws.com/cloudformation-stackset-sample-templates-us-east-1/AWSCloudFormationStackSetAdministrationRole.yml
https://s3.amazonaws.com/cloudformation-stackset-sample-templates-us-east-1/AWSCloudFormationStackSetExecutionRole.yml

それでは、先ほどのissueのコメントにならってCDKの実行ファイルを調整してみます。

調整前のループでスタックを作るコード

// HogeEnvなどをimport(省略)

const app = new cdk.App();

// リージョン毎にスタックを実行(HogeEnvは{ account: xxxx, region: yyyy }の配列)
HogeEnv.forEach(env => {
    new HogeStack(app, 'HogeStack', { env });
});

調整後のStackSetsでスタックを作るコード

// envなどをimport(省略)

const app = new cdk.App();

// デプロイしたいスタックからテンプレート文字列を生成
const stage = new cdk.Stage(app, 'Staging');
new DeployCDKAsAStackSetsStack(stage, 'DeployCDKAsAStackSetsStack', { env });
const stackSetTemplateObj = stage.synth().stacks[0].template;

// StackSetsを作成するためのCloudFormationスタックを作成
const stackSetDeployer = new cdk.Stack(app, 'StackSetDeployer');
// テンプレート文字列を使ってStackSetsを作成
new cdk.CfnStackSet(stackSetDeployer, 'DeployCDKAsAStackSets', {
    permissionModel: 'SELF_MANAGED',
    stackSetName: 'DeployCDKAsAStackSets',
    capabilities: ['CAPABILITY_NAMED_IAM'],
    stackInstancesGroup: [
        {
            deploymentTargets: {
                accounts: [env.account],
            },
            regions: ['デプロイするリージョン', ...],
        },
    ],
    templateBody: JSON.stringify(stackSetTemplateObj),
});

今回は同一AWSアカウント内で複数のリージョンにデプロイするのが目的です。
そのため、デプロイするAWSアカウントはOrganizationsに依存しない形になります。
これらからpermissionModelにはSELF_MANAGEDを設定しました。

StackSetsを作成するためのパラメーターは以下のドキュメントをご参照ください。

class CfnStackSet (construct) · AWS CDK
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudformation.CfnStackSet.html#autodeployment

デプロイ結果

今回はus-east-1とap-northeast-1の2リージョンを['デプロイするリージョン', ...],に指定します。
実行するとCloudFormationコンソールのStackSetsで2リージョンにスタックが実行されているのが確認できました。

同コンソールのスタック-スタックの詳細ではStackSetsを作成するためのstackSetDeployerスタックが作成され、
その後にStackSets経由で実際にデプロイしたいDeployCDKAsAStackSetsStackスタックが作成・実行されたことがわかります。

最後に

いかがでしたでしょうか?
2023年2月現在CDKのCloudFormation StackSets連携はサポートはされていませんが、
StackSetsを作成するスタックを定義することでCDKからStackSetsの作成ができることが確認できました。

冒頭のCDK内でループさせてスタックを作る方法だと、各リージョンでcdk bootstrapする必要がありました。
また、デプロイコマンドもcdk deploy --allとなって少々力業な感じが否めません。

StackSetsを作成する方法だと、記述量は増えてしまいますがIAMロールを2つ用意するだけで全リージョンのスタックを作成できるためスッキリとした構成にすることができました。
引き続き改善を進めていきたいと思います!

スタイル・エッジ・グループでは一緒に働く仲間を募集しております。
興味をお持ち頂けましたら是非とも下記をクリックしてください↓↓

recruit.styleedge-labo.co.jp