Claude Media
Claude CodeでAWS CDKスタックを書く — TypeScriptとPythonの実装フロー

Claude CodeでAWS CDKスタックを書く — TypeScriptとPythonの実装フロー

Claude CodeでAWS CDKスタックを書く手順を、環境構築からBash権限設計、TypeScript/Pythonの書き分け、cdk deployの確認フローまで扱います。

Claude CodeでAWS CDKスタックを書くとは

Claude CodeでAWS CDKスタックを書くとは、TypeScriptやPythonといった汎用言語でAWSリソースを定義することです。コードの生成とcdkコマンドの実行はClaude Codeに任せます。AWS CDK(AWS Cloud Development Kit)は、インフラをコードで管理するIaC(Infrastructure as Code)のフレームワークです。書いたコードは最終的にAWS CloudFormationのテンプレートへ変換され、デプロイされます。CDK v1は2023年6月1日にサポートが終了しており、現行はv2です。

CDKのコードはAppStackConstructという3階層で構成されます。Appインスタンスの中に1つ以上のStackを作り、Stackの中でAWSリソースを表すConstructを組み立てます。この階層構造はTypeScriptとPythonで見た目こそ違いますが、意味は共通です。型ヒントやクラス構造で表現されるぶん、Claude Codeにとっても仕様書とコードの区別がつきやすい対象になります。この記事では、環境構築からBash権限の設計、TypeScript/Pythonの書き分け、変更を確認してから反映するまでの流れを扱います。

環境をセットアップする

前提として、使用する言語に関わらずNode.js 22.x以降が要ります。CDKの各言語ランタイムは同じバックエンドで動き、そのバックエンドがNode.js上で動作するためです。加えてTypeScriptなら3.8以降、Pythonなら3.9以降(pipvirtualenv込み)が必要です。AWSアカウントとAWS CLIの設定も事前に済ませておきます。

最初にCDK CLIをインストールします。Node Package Managerでグローバルにインストールするのが公式の推奨です。

npm install -g aws-cdk
cdk --version

複数バージョンを使い分けたい場合は、プロジェクトごとにローカルインストールしてnpx aws-cdkで呼び出す方法もあります。デプロイには、実行環境に設定されたAWSの認証情報が要ります。CDK CLIはAWS CLIで設定した認証情報をそのまま使います。IAM Identity Centerのユーザーならaws configure sso、IAMユーザーならaws configureで設定します。プロファイルを複数使う場合は、CDK CLIの--profileオプションで指定します。

プロジェクトを作るときは、cdk initにテンプレート名と言語を渡します。

mkdir hello-cdk && cd hello-cdk
cdk init app --language typescript

Pythonの場合は、初期化後に仮想環境の有効化と依存インストールが追加で要ります。

cdk init app --language python
source .venv/bin/activate
python -m pip install -r requirements.txt

cdk initで作られるディレクトリ名は、生成されるコード内の命名にも使われるため、名前はcdk initの前に決め切っておきます(理由は後述の「よくあるつまずき」で扱います)。

最後に、デプロイ先のAWS環境を一度だけ準備します。

cdk bootstrap

プロジェクトのルートから実行すれば、環境情報はプロジェクトから自動で取得されます。

Bash権限でcdkコマンドの実行範囲を決める

cdkサブコマンドは、ローカルで完結するものとAWS上のリソースを変更するものが混在します。cdk synthはコードからCloudFormationテンプレートを生成するだけの操作で、AWSへの接続を伴いません。一方cdk deployはCloudFormationを通じて実際にリソースを作成・変更し、cdk destroyはスタックとその中のリソースを削除します。Claude Codeの権限設定はBash(<コマンド>)という形式のルールで、*を使えば一群のコマンドを1つのルールでまとめて扱えます。

{
  "permissions": {
    "allow": ["Bash(cdk synth)", "Bash(cdk diff)", "Bash(cdk list)"],
    "ask": ["Bash(cdk deploy *)"],
    "deny": ["Bash(cdk destroy *)"]
  }
}

cdk deployは既定(--require-approval broadening)で、IAM文の追加や権限・セキュリティグループの拡大を伴う変更のときだけ対話のy/n確認を挟みます。公式チュートリアルの実行例では、Lambda用のIAMロール作成が次のように提示されます。

IAM Statement Changes
┌───┬───────────────────────────────────────┬────────┬──────────────────────────┐
│ + │ ${HelloWorldFunction/ServiceRole.Arn} │ Allow  │ sts:AssumeRole           │
└───┴───────────────────────────────────────┴────────┴──────────────────────────┘
Do you wish to deploy these changes (y/n)?

このy/nはCDK CLI自身が出す対話プロンプトで、答えるには標準入力(TTY)が要ります。Claude CodeのBashツールにはTTYが無いため、askルールでClaude Code側の許可を一度通しても、その先にあるCDK側のy/nにはClaude Codeから答えられず、そのままではデプロイは完了しません。Claude Code経由でも実際に回すには、依頼するコマンドに--require-approval neverを付けてCDK側の確認自体を無くし、承認の判断はClaude Codeのaskルール(実行前に人間が許可・拒否する)だけに一本化します。any-changeや既定のbroadeningのまま対話確認を使いたい場合は、cdk deployは自分のターミナルで直接実行し、y/nにはその場で答えます。承認の判断をClaude Codeのaskルールに一本化するときは、許可の前にcdk diffの出力でIAM変更の内容を確認する運用を挟むと、内容を見ないまま許可することを避けられます。

より強く介入したい場合は、PreToolUseフックでcdk deploycdk destroyの呼び出し自体を検査する方法もあります。対象スタック名やリージョンによって拒否・確認強制・素通しを切り替えられます。フックの判定はallow/askルールより優先されるため、拒否コード(exit code 2)を返せば許可リストに関係なく実行を止められます。

CLAUDE.mdでTypeScript/Pythonの書き分けを固定する

CLAUDE.mdはセッション開始時に毎回読み込まれるファイルで、プロジェクト全体に効かせたい規約を置く場所です。AWS CDKはTypeScript・Python・Java・C#・Goに対応していますが、同じFunctionコンストラクトでも言語ごとに書き方の慣習が変わります。

観点TypeScriptPython
プロパティの渡し方TypeScript1つのオブジェクト引数Pythonキーワード引数
プロパティ名の書式TypeScriptcamelCasePythonsnake_case
インスタンス化TypeScriptnewキーワードを使うPythonnewは使わない
scope引数の慣習名TypeScriptthisPythonself
モジュールの読み込みTypeScriptimport { aws_s3 as s3 } from 'aws-cdk-lib'Pythonimport aws_cdk.aws_s3 as s3

この違いをCLAUDE.mdに明文化しておくと、Claude Codeが言語をまたいで実装するときにも書式が揺れにくくなります。

# CDKスタック実装の規約
- このプロジェクトの言語はPythonに統一する(TypeScriptのコード例をそのまま移植しない)
- プロパティはキーワード引数で渡し、snake_caseで命名する
- コンストラクトのscope引数は必ず`self`で受け取る

スタックとLambda関数を実装させる

cdk initで作られたスタックファイルには、Stackを継承した空のクラスが1つ用意されています。TypeScriptの場合は次のような形です。

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
 
export class HelloCdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    // Define your constructs here
  }
}

Pythonではselfを使い、キーワード引数で親クラスを呼び出します。

from aws_cdk import Stack
from constructs import Construct
 
class HelloCdkStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        # Define your constructs here

ここにAWS Construct LibraryのFunctionを追加すると、Lambda関数がリソースとして定義されます。TypeScriptの例です。

import * as lambda from 'aws-cdk-lib/aws-lambda';
 
const myFunction = new lambda.Function(this, "HelloWorldFunction", {
  runtime: lambda.Runtime.NODEJS_20_X,
  handler: "index.handler",
  code: lambda.Code.fromInline(`
    exports.handler = async function(event) {
      return { statusCode: 200, body: JSON.stringify('Hello World!') };
    };
  `),
});

Functionのようなコンストラクトは、どの言語でも同じ3つの引数(scope・id・props)を取ります。scopeは親となるStackインスタンス、idはアプリ内で構成要素を一意に識別する構成ID、propsはランタイムやハンドラー名などの設定値です。Pythonではpropsがキーワード引数に展開される点だけが変わります。

from aws_cdk import aws_lambda as _lambda
 
my_function = _lambda.Function(
    self, "HelloWorldFunction",
    runtime=_lambda.Runtime.NODEJS_20_X,
    handler="index.handler",
    code=_lambda.Code.from_inline("""
        exports.handler = async function(event) {
          return { statusCode: 200, body: JSON.stringify('Hello World!') };
        };
    """),
)

構成IDのHelloWorldFunctionは、デプロイ時に位置情報から生成されるハッシュと組み合わさって、実際のAWSリソース名の一部になります。Claude Codeに実装を任せる際も、この構成IDをコンストラクトの追加・削除のたびに変えないようにしておくと、再デプロイ時に既存リソースが意図せず置き換わる事態を避けやすくなります。

変更を依頼するときは、変えてよい範囲を具体的に指定すると事故を防げます。

HelloWorldFunctionの構成IDとruntimeは変えずに、handlerだけindex.handlerからapp.handlerに変更して。変更したらcdk synthを実行して、差分がハンドラー名以外に及んでいないか出力を見せて」

このように依頼すると、Claude Codeは構成IDを保持したまま該当プロパティだけを書き換え、cdk synthの出力を提示させられます。生成されたテンプレートのPropertiesを見れば、意図しないリソースの追加・削除が起きていないかをデプロイ前に確認できます。

cdk diff / cdk synth / cdk deployで変更を確認してから反映する

スタックを書き終えたら、まずcdk listでアプリ内のスタック名を確認します。

cdk list
cdk synth

cdk synthはコードを実行してCloudFormationテンプレートを生成し、標準出力にYAML形式で表示します。この時点ではAWSへの接続は発生しません。テンプレートに問題がなければcdk deployで反映します。

cdk deploy

すでにデプロイ済みのスタックを変更した場合は、cdk diffで差分だけを先に確認できます。デプロイが完了すると、CDK CLIはスタックのARNや出力値(Lambda関数URLなど)を表示します。スタックが不要になったらcdk destroyで削除します。

cdk destroy

cdk destroyも既定では削除前にAre you sure you want to delete: HelloCdkStack (y/n)?という対話確認を挟みます。これもCDK CLI自身のプロンプトなので、TTYの無いClaude Code上ではこのy/nにClaude Codeから答えることができません。前段の権限設定をdenyにしておけば、この確認に辿り着く前にClaude Code側で実行がブロックされ、破壊的操作を人の手に残せます。Claude Code経由で削除まで自動化したい場合は、denyaskに変えたうえでコマンドに--force(-f)を付けてCDK側の確認をスキップし、承認の判断をClaude Codeのaskルールだけに委ねます。公式チュートリアルの実行例では、デプロイ完了までに数十秒かかっています。会話を止めずに進めたい場合は、Ctrl+Bでコマンドを裏に回すClaude Codeバックグラウンド実行が参考になります。

よくあるつまずき

npx cdk deployが許可ルールに引っかからない

Bash(cdk deploy *)という許可ルールを書いても、Claude Codeがnpx cdk deployとしてコマンドを組み立てた場合はルールが一致せず、毎回確認を求められます。npxはClaude Codeが自動で読み飛ばすラッパーの一覧に含まれないためです。ローカルインストールしたCDK CLIをnpx経由で使う運用なら、npxを含めた形でルールを書き直します。

Pythonの仮想環境を有効化し忘れる

cdk init --language pythonのあと、.venvの有効化とpip install -r requirements.txtを忘れたままコマンドを進めるとどうなるでしょうか。aws_cdkモジュールが見つからないというエラーで、cdk synthcdk deployが失敗します。TypeScript側では対応する手順が不要なため、言語を切り替えるたびにこの一手間を忘れがちです。

ディレクトリ名を後から変える

公式ドキュメントは、チュートリアル用ディレクトリを作る際に「このディレクトリ名を変えないこと」を明示の注意事項にしています。cdk init実行後にディレクトリ名を変更すると、既に生成済みのApp・Stackファイル内の命名と食い違う可能性があるためです。Claude Codeに後からディレクトリ名の変更を頼むと、生成済みのidや参照がずれる余地があります。命名をやり直したい場合は、ディレクトリを変更するより先にコード内のAppStackのidを揃えて書き直すほうが安全です。

cdk bootstrapを忘れたままデプロイする

cdk bootstrapは、CDKのデプロイに使うAWS環境を事前に準備する一度限りの手順です。まだブートストラップしていない環境に対してcdk deployを実行すると、デプロイが失敗します。新しいAWSアカウントやリージョンで初めてCDKを使うときは、cdk deployより先にcdk bootstrapを実行したかを確認します。

まとめ

Claude CodeでAWS CDKスタックを書く流れは、CDK CLIのインストールとプロジェクト初期化から始まります。cdk synthcdk deployの間にBash権限やPreToolUseフックで確認の層を挟み、CLAUDE.mdで言語ごとの書き分けを固定するところまでが1セットです。TypeScriptとPythonではnewの有無や引数の渡し方が変わるだけで、AppStackConstructという構造自体は共通しています。

テンプレートの構文チェックやコンプライアンス確認、デプロイ失敗時の原因診断まで自動化したいなら、次のステップはCloudFormation/CDKをMCPで自動検証するです。Terraformと使い分けたい場合はTerraform MCPサーバーの使い方が参考になります。破壊的操作をauto modeがどこまで止めるかは、Claude Code auto modeブロック一覧で確認できます。

この記事を共有:XはてブLinkedIn