課題1:cdk deployをする時の認証情報をどこに持つか

大村幸敬氏(以下、大村):ここからは、すでにCDKを使っている方向けにレベルを上げたナレッジをお伝えします。「cdk deployをする時の認証情報をどこに持つか」という問題があります。普通の手順でやると何が起きるか。GitHubからコードを持ってきます、自分の手元の端末にAPIキー、アクセスキーを持っておいて、その認証情報でcdk deployをしていきます。

手元の端末から対象の環境にデプロイしていくわけですが、この場合、当然手元にcdk deployができるぐらいの権限を持っておくことになるわけです。しかし、それを誰かに取られてしまうと同じくらいの作業ができてしまう。そう考えるとそこそこレベルの高い権限を持っておくのはちょっと怖い。

では、手元にまったく認証情報を持たずにやれるのか。実はAWS SSOを使う方法があります。AWSのCLI v2がAWS SSOと連携する仕組みを持っていて、aws sso loginというコマンドを叩けば、(スライドを示して)~/.aws/configの中に設定されている内容、プロファイルに従ってAWS SSOのログイン画面がブラウザに出てきます。

そこでID、パスワード、MFA(Multi-Factor Authentication)トークンなどを入力してログインしたら、またターミナル側に戻ってくる。戻ってくるというかフォーカスが移るくらいですが、戻ってきたあとはそのプロファイルを使えば、いろいろなAPIを呼べる。CLI(Command Line Interface)が操作できるというやつです。これを使えば手元に認証情報を持っておく必要がなく、1回ログインすればキャッシュされた認証情報で操作できます。

「じゃあCDKで一発じゃん!」と思っていたけれど、以前は、それこそ1ヶ月前(登壇時2022年4月)まではうまく動かなかった。内部的にCLIが引っ張ってくるテンポラリ(一時的)のクレデンシャル(認証情報)をCDKのコマンドに渡す動作がうまくできておらず、ラッパーのプログラムをかます必要があったんです。現在BLEA(Baseline Environment on AWS)に書いてある手順の内容も、そのようになっています。

ところが、3月に出たバージョン2.18.0では、AWS SSOの認証情報がCDKから直接利用可能になりました。設定が非常にシンプルになりました。スライドのプロファイルをご覧ください。AWS SSOに関する情報を書いておけば、aws sso loginを1回プロファイル指定して叩いたあとcdk deployを叩いて、そのプロファイルを指定すればそのままCDKも実行できます。これは非常にやりやすいです。

課題2:パラメーターを切り替えて使う

大村:次は、パラメーターを切り替える話です。本番環境や開発環境において違うパラメーターでどうデプロイするか。解決策はいろいろありますが、まずBLEAではcdk.jsonの中のcontextに設定値のグループを保持しておいて、環境によってそのグループを切り替えます。先ほどもどなたかが発表していましたが、よく考えられるやり方だと思います。

CDKのコマンドを実行する時、私たちは-cというオプションでenvironmentという名前を使っていますが、それにdevやprodや値を入れることによって、その値のグループを切り替えて使えるようにします。

コードの中ではtryGetContextで値を引っ張ってくる、あとはそれをディクショナリから引っ張って使うように書いています。(スライドを示して)BLEAでは現状このようにコンテキストの値を使ってパラメーターを管理しています。

いくつかパラメーターを扱う考え方があります。BLEAというよりCDK一般の考え方でもありますが、ややこしい言葉がいくつかあるんです。

お伝えしたいのは「Parameters」と呼ばれるもので、CDKのドキュメントの中にも書いてあります。書いてあるけれど実は使ってはいけないもので、内部的にCloudFormationのテンプレートに渡すパラメーターのことを言っています。ドキュメントのほうにも、「一般的にParametersを使うことを推奨しません」と明確に書いてあります。これを使うのではなく、コンテキストか環境変数を使ってください。用途が違うんです。Parametersは使いません。BLEAの中でも使っていません。

環境変数です。極端な話、環境変数にいろいろな情報を持たせておいて、それを引っ張ってくるやり方もできなくはありませんが、その時はCDKを使う前の段階で何か環境変数を取り込んだり設定したりするものを用意しておいて管理しなければいけないわけです。コマンドラインで指定するだけだと記録は残らないので、どこに何の環境変数を指定したかがわからなくなってしまいます。

ただ、環境変数を管理するために、例えばシェルスクリプトを用意するのも、これはこれでやりにくいと思います。GitHubできちんと構成が管理ができなくなってしまう。環境変数についても、BLEAの中ではデフォルトのアカウントとリージョンを使っています。つまり、(CLIの)プロファイル、認証情報に紐づくアカウントとリージョンの情報だけは使っていますが、それも本当に限定した使い方です。

実際はスライドの一番上のcontextの値を使っていて、contextの中に設定されている情報をメインで使います。唯一お伝えしたいのは、私たちはenvというパラメーターでデプロイ先のアカウントとリージョンがどこなのかを指定するようにしています。これはフールプルーフになっていて、デプロイする時にプロファイルとコンテキストを指定します。

要は、認証情報としてどこのアカウントにデプロイするか、パラメーターとしてどこのアカウントにデプロイするつもりのパラメーターなのか。その2つを指定しますが、もし違っていた場合、つまりぜんぜん違う環境のパラメーターをぜんぜん違う環境にデプロイしようとした場合は、スライドに書かれている値と実際に認証情報として与えられたアカウントが違うのでデプロイできないフールプルーフがかかるようになっています。

一方、開発環境みたいに、今ある手元のパラメーターをどの環境にも、どのアカウントにもデプロイしたい場合もあると思っています。その場合はenvを指定しなければいい。envを指定しない場合は環境変数から値を取ってくるというロジックを内部に持っています。コードはそんなに難しくないので、また見てもらえればと思っています。

パラメーターについては、いろいろ考えるところがあるのではないかと思います。先ほども話したように、「そもそもパラメーターで切り替えるほうがいいのか」という問題がある。例えば私は、RDS(Relational Database Service)のバックアップに成功した・失敗したみたいなイベントをSlackに投げる設定をCDKでしました。

開発環境はもういいです。何が起きても別に通知はいりません、一方で本番環境は通知したいとなったら、そこで条件分岐ができるわけです。開発なら・本番なら、という話になります。1つだけならいいですが、あちこちに出てくるとコードの内容と実体がどっちなのかがよくわからなくなると思います。

そうなるくらいなら、スライドのようにパラメーターだけ別でコードが一緒なのではなく、だいぶ似た内容ですが、まったく別のコードとして、差分はdifを取りながら確認していくという管理の仕方もありなのではないかと考えています。ここは複雑度によってチョイスすることになると思います。

私たちはBLEAのコードをインターネットに公開しているわけですが、開発環境用のパラメーターをどこに置いておくかという問題があります。通常の用途なら全部プライベートの環境にあるので、社内のIPアドレスだのなんだのにを​​置いていていいと思いますが、(コードを公開する)私たちの場合は.gitignoreに何を入れて、パラメーターをどこから引っ張るかという問題がありました。

やや行儀が悪いしベストプラクティスからズレますが、私はcdk.context.jsonに自分の手元だけの環境を置き、cdk.context.jsonを.gitignoreに入れておいて、コミットしないようにしながらやっています。でも、(この方法は)ドキュメント上では「おすすめしない」と書いてあったりしますけれども。

ほかに${HOME}/.cdk.json を使う、Parameter Storeを使う、S3を使うなどいろいろあり得ると思いますが、私たちも「これがいい」という答えを持っていません。

「そもそもコンテキストを使ったほうがいいんだろうか」という問題もあると思います。コンテキストは基本的にjsonなので、パラメーターの型チェックもそのままではできないし、jsonの書き方をしなければいけないし、面倒ですから。

となれば独自の設定ファイルを作って読み込む方式を実装していくことが考えられますが、何らかしらの設計を行って実装しなければいけない。CDKのデフォルトのライブラリにありそうですが、まだないんです。確か以前のCDKミートアップで話してもらったものの中には「こういうライブラリを作ってみました」という方もいました。いろいろ方式は考えられるんですが、「んー、どうかな」という感じです。何かいい方法が標準的に決まればいいとは思っています。

課題3:パイプラインをどうデザインするか

大村:「パイプラインをどうデザインするか」という問題があります。(スライドを示して)手書きで申し訳ありませんが、順番に説明すると、よくあるのは開発環境・ステージング環境・本番環境です。今はすべて別のアカウントという想定で書いています。

基本的に開発環境は開発者が自由にできる環境であって、1人1つずつある感じです。ここでスタックをテストして、それがよければステージングに行き、本番に行き、追加のテストをやっていくことになると思いますが、そう考えた時に「パイプラインはこうやってみたらどうか」という考え方です。

今、CDKパイプラインというオフィシャルで出しているパイプラインのライブラリがありますが、BLEAではそれを使ったサンプルコードを出そうとしています。そのデザインですが、開発者はいったんパイプラインなしで手元でいろいろとやりたいだろうと思って、直接スタックを作ってテストを行うことを考えます。パイプラインはパイプライン専用のアカウントを作る。ステージング用と本番用はそれぞれ同じパイプラインですが、別々に作ります。これは同じコードから作られます。

お行儀が悪いですが、ステージング環境のパイプラインはステージング環境がきちんと動くことで動作確認をするようにしておいて、パイプラインを走らせてステージング環境のほうにデプロイする。これがうまくいけば最後は本番です。本番には本番用のパイプラインを使ってコードをデプロイする。こういうやり方はどうかと、今は考えています。まだ(コードは)出せていませんが、今はこういうかたちで実装しようとしています。

情報をまとめました。

パイプラインのデザインに関しては取り得る選択肢がたくさんあるので、「これ」というのはあまり決まらないのだろうと思います。

大事なのは、ターゲットのスタックのどんなテストをどの環境でやるのかです。手元でやるのか、ステージング環境のみんな共有のところでやるのかを考えること。

あとはオーナーです。アカウントの分割に影響します。例えばデプロイ専門のチームがいる、運用チームみたいなものがいる場合。そうではなくて、デプロイから環境を作って運用するところまで1つのチームでやる場合など、チームの編成によってパイプラインのデザインも変わると思います。それ次第でパイプラインアカウントがあったほうがいいのか、はたまたデプロイ先のアカウントの中にパイプラインがあったほうがいいのかも決まってきます。

ほかに「CDKデプロイをどこで実行するか」という問題です。手元PCでやるとパイプラインになりませんが、GitHub Actionsから直接デプロイするのもありだし、パイプラインアカウントでもいいし、ターゲットアカウントでパイプラインを作ってもいいと思います。これも1つのデザインになります。今回、私たちはCDKパイプラインを使うので、GitHubから直接ではないかたちでデザインしています。

あとはCIをどこで実行するのか。私たちはGitHub Actionsの上でやっていますが、パイプライン上でやる手もあると思います。それからパイプラインスタック自体のテストをどこでやるのかということも、それぞれ検討事項になるのではないかと思います。みなさんがどう考えているかもぜひ聞きたいと思います。

課題4:複数のCDKプロジェクトをどう管理するか

大村:最後は「複数のCDKプロジェクトをどう管理するか」です。BLEAの場合、ユースケースを内部に持っています。ベースラインと呼ばれるセキュリティのベースとサンプルのコードという、まったく違う2つのプロジェクトを中に持っています。その時に、ディレクトリ構成をどうするのか。

多くのCDKのツールキットはルートの直下に1プロジェクトを置くことを想定しているわけですが、私たちはそうではないので、ユースケースという配下にそれぞれフォルダを掘りました。例えば、base-standaloneの下やguest-webapp-sampleの中にbinやlibがあったりするかたちで穴を掘ることにしました。

このまま各サブディレクトリでビルドしたら(個々でライブラリのダウンロードが発生して)容量の爆発が起きるので、NPM workspacesを使い、node_moduleのディレクトリを1つだけにして、あとはシンボリックリンクを自動的に引っ張るかたちで使えるようにデザインしています。

例えばWebアプリケーションのサンプルといっても、EC2を使うものやECS(Elastic Container Service)を使うものなどいくつかのパターンがあります。それについてはAppファイルを分けています。どのAppをビルドするのかによって違うスタックを組み合わせる。「各スタックの材料はこのlibの中に全部ある」というデザインにしています。

BLEAでは対応していませんが「アプリコードとインフラ系のコードをどう分けるか」という問題も出てきます。

今回は割愛しますが、その他の検討事項としていろいろやっていましたが、時間の関係で今日はこれ以上話しません。

今後もオープンソースで開発を継続していく

大村:(スライドを指して)BLEAの開発を通していろいろと試してきたことをお話ししました。今やってきた結果のコードをBLEAに置いてあります。今もオープンソースで開発を継続しているので、引き続きご覧になってください。How Toの中に、CDK開発の中でよく出てきそうな導入部分の手順なども書いてあるので、ぜひご覧になってください。

今日は、私たちがBLEAの開発の中で得られたナレッジについて話しました。@yktkoというアカウントでTwitterをやっているので、そちらに直接質問してくれてもいいですし、本日のハッシュタグを書いてくれれば見ます。ぜひ質問してください。以上です。ありがとうございました。

司会者:ありがとうございました。

(次回に続く)