ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

【体験談】初めての Kiro IDE で CloudFormation テンプレートを作ってみた

この記事を共有する

目次

はじめに

本記事では、筆者が初めて Kiro を使用し、AWS CloudFormation(以下、「CloudFormation」)のテンプレートファイルを作成した体験談について記載します。
AI コーディングの経験はほとんどありませんが、「習うより慣れよ」の精神で試行錯誤しながら Kiro を触ってみました。

先に結論を述べると、Kiro を使用するにあたり、以下を意識して開発することが重要だと学びました。

  • 要件を不足なく Kiro に明示すること
  • 要件に基づいて Spec ファイルをレビューし、不足や改善点を洗い出すこと
  • Kiro が提案するコマンド(特に実装時)は、確認してから実行すること
  • レビューの精度を上げるため、Spec ファイルを自身が理解しやすい形式に整理すること

Kiro で作成する成果物のイメージ

Kiro と対話しながら、以下の AWS リソースを構成する CloudFormation テンプレートを作成します。
作成したテンプレートは Kiro 経由で AWS に展開し、実際に AWS 上にリソースを構築することを目指します。

使用する AWS サービス

  • Amazon VPC(以下、「VPC」)
  • Amazon EC2(以下、「EC2」)
  • Amazon S3(以下、「S3」)
  • AWS Systems Manager Session Manager(以下、「Session Manager」)

構成図

構成の説明

  • EC2 インスタンスが S3 バケットへファイルをアップロード/ダウンロードする
  • EC2 インスタンスの OS メンテナンスのため、Session Manager でログインする
  • EC2 インスタンスは、S3 バケットと Session Manager と通信する際に VPC エンドポイントを経由する

Kiro の使用開始

Kiro のドキュメント「Installation - IDE - Docs - Kiro」¹に従って、Kiro をインストールしてログインします。
ログイン方法はいくつかありますが、筆者は AWS IAM Identity Center を使用しました。

ログイン後は Kiro の使い方に不明点があれば、ドキュメントを探すより先に Kiro 自身に質問して開発を進めていきます。
使用済み Credits を都度確認しつつ、自由に Kiro を試しました。

開発の流れ

開発方法は「Spec」を選択し、成果物の作成を目指して Kiro と対話します。
開発の流れを後述するにあたって、「Spec」の開発について簡単に説明します。

「Spec」の開発には 3 つの定義フェーズ「要件定義設計実装タスクの作成」があります。

各フェーズ毎に、内容を定義したファイル(Spec ファイル)を作成します。
各ファイルの名称と役割は、以下の内容(AWS ウェブマガジンからの引用²)になっています。

requirements.md : 要件・仕様を定義したファイル
design.md : 設計方針を定義したファイル
tasks.md : 実装のためのタスクリストがまとめられたファイル

Spec ファイルも「requirements.mddesign.mdtasks.md」の順番に作成します。
例えば「design.md」作成中に要件が追加された場合、「requirements.md」も同時に Kiro が修正します。

「tasks.md」の作成が完了したら定義は完了で、タスクリストに従って順次実装します。

要件定義

Kiro へ最初に次のようなチャットを送信しました。

CloudFormation で EC2 インスタンスと S3 バケットを作成して、通信させたい
日本語で回答してほしい

非常に曖昧な要件ですね。
Kiro はこの要件から、以下の返答を返してきました。

最後に「要件定義書の内容は問題ありませんか?よろしければ、次の設計フェーズに進みます。」と述べているように、Spec ファイルを作成すると次のフェーズへ進むか確認があります。
次に進む前に「requirements.md」の内容を確認します。

requirements.md

# 要件定義書
## はじめに
本ドキュメントは、CloudFormationを使用してEC2インスタンスとS3バケットを作成し、安全な通信を確立するインフラストラクチャ自動化機能の要件を定義します。この機能により、開発者はコードとしてインフラストラクチャを管理し、再現可能で一貫性のあるAWS環境を構築できます。
## 用語集
- **CloudFormation_Stack**: AWS CloudFormationによって管理されるリソースの集合
- **EC2_Instance**: Amazon Elastic Compute Cloudの仮想サーバーインスタンス
- **S3_Bucket**: Amazon Simple Storage Serviceのオブジェクトストレージバケット
- **IAM_Role**: AWS Identity and Access Managementのロール(権限セット)
- **Instance_Profile**: EC2インスタンスにIAMロールをアタッチするためのコンテナ
- **Security_Group**: EC2インスタンスのファイアウォールルール
- **Template**: CloudFormationテンプレート(YAML/JSON形式のインフラ定義ファイル)
- **Valid_Template**: CloudFormationの構文とスキーマに準拠したテンプレート
## 要件
### 要件1: CloudFormationテンプレートの作成
**ユーザーストーリー:** 開発者として、インフラストラクチャをコードとして定義できるように、CloudFormationテンプレートを作成したい
#### 受入基準
1. THE Template SHALL define an EC2_Instance resource with configurable instance type
2. THE Template SHALL define an S3_Bucket resource with appropriate naming
3. THE Template SHALL define an IAM_Role with S3 access permissions
4. THE Template SHALL define an Instance_Profile that associates the IAM_Role with the EC2_Instance
5. THE Template SHALL define a Security_Group for the EC2_Instance
6. THE Template SHALL use YAML format for readability
7. THE Template SHALL include parameters for customizable values (instance type, bucket name prefix)
8. THE Template SHALL include outputs for created resource identifiers
### 要件2: EC2インスタンスの設定
**ユーザーストーリー:** 開発者として、S3バケットにアクセスできるEC2インスタンスを自動的にプロビジョニングしたい
#### 受入基準
1. WHEN the CloudFormation_Stack is created, THE EC2_Instance SHALL be launched with the specified instance type
2. WHEN the EC2_Instance is launched, THE System SHALL attach the Instance_Profile to enable S3 access
3. WHEN the EC2_Instance is launched, THE System SHALL associate the Security_Group with the instance
4. THE EC2_Instance SHALL use the latest Amazon Linux 2 AMI
5. WHERE a key pair name is provided, THE EC2_Instance SHALL be configured with SSH access
### 要件3: S3バケットの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスからアクセス可能なS3バケットを作成したい
#### 受入基準
1. WHEN the CloudFormation_Stack is created, THE S3_Bucket SHALL be created with a unique name
2. THE S3_Bucket SHALL enable versioning for data protection
3. THE S3_Bucket SHALL enable server-side encryption by default
4. THE S3_Bucket SHALL block public access by default
5. WHEN the CloudFormation_Stack is deleted, THE S3_Bucket SHALL be retained to prevent data loss
### 要件4: IAMロールと権限の設定
**ユーザーストーリー:** 開発者として、EC2インスタンスがS3バケットに安全にアクセスできるように、適切な権限を設定したい
#### 受入基準
1. THE IAM_Role SHALL grant the EC2_Instance permission to list objects in the S3_Bucket
2. THE IAM_Role SHALL grant the EC2_Instance permission to read objects from the S3_Bucket
3. THE IAM_Role SHALL grant the EC2_Instance permission to write objects to the S3_Bucket
4. THE IAM_Role SHALL grant the EC2_Instance permission to delete objects from the S3_Bucket
5. THE IAM_Role SHALL follow the principle of least privilege (access only to the created S3_Bucket)
6. THE IAM_Role SHALL have a trust policy that allows EC2 service to assume the role
### 要件5: セキュリティグループの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスへの安全なアクセスを制御したい
#### 受入基準
1. THE Security_Group SHALL allow inbound SSH traffic (port 22) from specified CIDR blocks
2. THE Security_Group SHALL allow all outbound traffic to enable S3 access
3. WHERE no CIDR block is specified, THE Security_Group SHALL default to allowing SSH from 0.0.0.0/0 with a warning
4. THE Security_Group SHALL include a description for each rule
### 要件6: スタックのデプロイと管理
**ユーザーストーリー:** 開発者として、CloudFormationスタックを簡単にデプロイ、更新、削除できるようにしたい
#### 受入基準
1. WHEN a Valid_Template is provided to CloudFormation, THE System SHALL create all defined resources
2. WHEN the CloudFormation_Stack creation fails, THE System SHALL rollback all created resources
3. WHEN the CloudFormation_Stack is updated with a Valid_Template, THE System SHALL modify only the changed resources
4. WHEN the CloudFormation_Stack is deleted, THE System SHALL remove all resources except those with retention policies
5. THE Template SHALL validate successfully using CloudFormation validation tools
### 要件7: 出力とリソース情報
**ユーザーストーリー:** 開発者として、作成されたリソースの情報を簡単に取得したい
#### 受入基準
1. WHEN the CloudFormation_Stack is created, THE System SHALL output the EC2_Instance ID
2. WHEN the CloudFormation_Stack is created, THE System SHALL output the S3_Bucket name
3. WHEN the CloudFormation_Stack is created, THE System SHALL output the EC2_Instance public IP address
4. WHEN the CloudFormation_Stack is created, THE System SHALL output the IAM_Role ARN
5. THE outputs SHALL be accessible through CloudFormation console and CLI
### 要件8: テンプレートの検証
**ユーザーストーリー:** 開発者として、テンプレートが正しい構文とベストプラクティスに従っていることを確認したい
#### 受入基準
1. THE Template SHALL be valid according to CloudFormation schema
2. THE Template SHALL include all required resource properties
3. THE Template SHALL use intrinsic functions correctly (Ref, GetAtt, Sub, etc.)
4. THE Template SHALL define dependencies between resources where necessary
5. WHEN the Template is validated using AWS CLI, THE System SHALL return success without errors

「受け入れ基準」が英語で記載されています。
受け入れ基準を日本語で記載してほしい」と指示すると、日本語に修正してくれました。

requirements.md

# 要件定義書
## はじめに
本ドキュメントは、CloudFormationを使用してEC2インスタンスとS3バケットを作成し、安全な通信を確立するインフラストラクチャ自動化機能の要件を定義します。この機能により、開発者はコードとしてインフラストラクチャを管理し、再現可能で一貫性のあるAWS環境を構築できます。
## 用語集
- **CloudFormation_Stack**: AWS CloudFormationによって管理されるリソースの集合
- **EC2_Instance**: Amazon Elastic Compute Cloudの仮想サーバーインスタンス
- **S3_Bucket**: Amazon Simple Storage Serviceのオブジェクトストレージバケット
- **IAM_Role**: AWS Identity and Access Managementのロール(権限セット)
- **Instance_Profile**: EC2インスタンスにIAMロールをアタッチするためのコンテナ
- **Security_Group**: EC2インスタンスのファイアウォールルール
- **Template**: CloudFormationテンプレート(YAML/JSON形式のインフラ定義ファイル)
- **Valid_Template**: CloudFormationの構文とスキーマに準拠したテンプレート
## 要件
### 要件1: CloudFormationテンプレートの作成
**ユーザーストーリー:** 開発者として、インフラストラクチャをコードとして定義できるように、CloudFormationテンプレートを作成したい
#### 受入基準
1. Template は、設定可能なインスタンスタイプを持つ EC2_Instance リソースを定義しなければならない
2. Template は、適切な命名規則を持つ S3_Bucket リソースを定義しなければならない
3. Template は、S3アクセス権限を持つ IAM_Role を定義しなければならない
4. Template は、IAM_Role を EC2_Instance に関連付ける Instance_Profile を定義しなければならない
5. Template は、EC2_Instance 用の Security_Group を定義しなければならない
6. Template は、可読性のために YAML 形式を使用しなければならない
7. Template は、カスタマイズ可能な値(インスタンスタイプ、バケット名プレフィックス)のためのパラメータを含まなければならない
8. Template は、作成されたリソース識別子のための出力を含まなければならない
### 要件2: EC2インスタンスの設定
**ユーザーストーリー:** 開発者として、S3バケットにアクセスできるEC2インスタンスを自動的にプロビジョニングしたい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、EC2_Instance は指定されたインスタンスタイプで起動されなければならない
2. EC2_Instance が起動されたとき、System は S3 アクセスを有効にするために Instance_Profile をアタッチしなければならない
3. EC2_Instance が起動されたとき、System は Security_Group をインスタンスに関連付けなければならない
4. EC2_Instance は最新の Amazon Linux 2 AMI を使用しなければならない
5. キーペア名が提供される場合、EC2_Instance は SSH アクセスで設定されなければならない
### 要件3: S3バケットの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスからアクセス可能なS3バケットを作成したい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、S3_Bucket は一意の名前で作成されなければならない
2. S3_Bucket は、データ保護のためにバージョニングを有効にしなければならない
3. S3_Bucket は、デフォルトでサーバー側暗号化を有効にしなければならない
4. S3_Bucket は、デフォルトでパブリックアクセスをブロックしなければならない
5. CloudFormation_Stack が削除されたとき、S3_Bucket はデータ損失を防ぐために保持されなければならない
### 要件4: IAMロールと権限の設定
**ユーザーストーリー:** 開発者として、EC2インスタンスがS3バケットに安全にアクセスできるように、適切な権限を設定したい
#### 受入基準
1. IAM_Role は、EC2_Instance に S3_Bucket 内のオブジェクトをリストする権限を付与しなければならない
2. IAM_Role は、EC2_Instance に S3_Bucket からオブジェクトを読み取る権限を付与しなければならない
3. IAM_Role は、EC2_Instance に S3_Bucket へオブジェクトを書き込む権限を付与しなければならない
4. IAM_Role は、EC2_Instance に S3_Bucket からオブジェクトを削除する権限を付与しなければならない
5. IAM_Role は、最小権限の原則に従わなければならない(作成された S3_Bucket のみへのアクセス)
6. IAM_Role は、EC2 サービスがロールを引き受けることを許可する信頼ポリシーを持たなければならない
### 要件5: セキュリティグループの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスへの安全なアクセスを制御したい
#### 受入基準
1. Security_Group は、指定された CIDR ブロックからのインバウンド SSH トラフィック(ポート22)を許可しなければならない
2. Security_Group は、S3 アクセスを有効にするためにすべてのアウトバウンドトラフィックを許可しなければならない
3. CIDR ブロックが指定されていない場合、Security_Group は警告付きで 0.0.0.0/0 からの SSH を許可するようデフォルト設定されなければならない
4. Security_Group は、各ルールの説明を含まなければならない
### 要件6: スタックのデプロイと管理
**ユーザーストーリー:** 開発者として、CloudFormationスタックを簡単にデプロイ、更新、削除できるようにしたい
#### 受入基準
1. Valid_Template が CloudFormation に提供されたとき、System は定義されたすべてのリソースを作成しなければならない
2. CloudFormation_Stack の作成が失敗したとき、System は作成されたすべてのリソースをロールバックしなければならない
3. CloudFormation_Stack が Valid_Template で更新されたとき、System は変更されたリソースのみを変更しなければならない
4. CloudFormation_Stack が削除されたとき、System は保持ポリシーを持つリソースを除くすべてのリソースを削除しなければならない
5. Template は、CloudFormation 検証ツールを使用して正常に検証されなければならない
### 要件7: 出力とリソース情報
**ユーザーストーリー:** 開発者として、作成されたリソースの情報を簡単に取得したい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、System は EC2_Instance ID を出力しなければならない
2. CloudFormation_Stack が作成されたとき、System は S3_Bucket 名を出力しなければならない
3. CloudFormation_Stack が作成されたとき、System は EC2_Instance のパブリック IP アドレスを出力しなければならない
4. CloudFormation_Stack が作成されたとき、System は IAM_Role ARN を出力しなければならない
5. 出力は、CloudFormation コンソールと CLI を通じてアクセス可能でなければならない
### 要件8: テンプレートの検証
**ユーザーストーリー:** 開発者として、テンプレートが正しい構文とベストプラクティスに従っていることを確認したい
#### 受入基準
1. Template は、CloudFormation スキーマに従って有効でなければならない
2. Template は、すべての必須リソースプロパティを含まなければならない
3. Template は、組み込み関数(Ref、GetAtt、Sub など)を正しく使用しなければならない
4. Template は、必要に応じてリソース間の依存関係を定義しなければならない
5. Template が AWS CLI を使用して検証されたとき、System はエラーなしで成功を返さなければならない

その後、想定する成果物に近づけるため、各フェーズを通じて以下の指示を行いました。

  • AMI を Amazon Linux 2 から Amazon Linux 2023 に変更する
  • EC2 インスタンスにはパブリック IP を付与せず、インターネットからのアクセスを許可しない
  • EC2 インスタンスには SSH でアクセスせず、Session Manager でアクセスする
  • EC2 インスタンスにアタッチする IAM ロールでは、S3 オブジェクト削除を許可しない。また、AWS Systems Manager へのアクセスを許可する
  • EC2 インスタンスにアタッチするセキュリティグループでは、インバウンド通信の許可は不要とする
  • 各リソースに命名規則に沿った Name タグをアタッチする
  • EC2 インスタンスは S3 バケットと Session Manager との通信に VPC エンドポイント を使用する

開発完了時点の「requirements.md」は次の内容になりました。

requirements.md

# 要件定義書
## はじめに
本ドキュメントは、CloudFormationを使用してEC2インスタンスとS3バケットを作成し、安全な通信を確立するインフラストラクチャ自動化機能の要件を定義します。この機能により、開発者はコードとしてインフラストラクチャを管理し、再現可能で一貫性のあるAWS環境を構築できます。
## 用語集
- **CloudFormation_Stack**: AWS CloudFormationによって管理されるリソースの集合
- **EC2_Instance**: Amazon Elastic Compute Cloudの仮想サーバーインスタンス
- **S3_Bucket**: Amazon Simple Storage Serviceのオブジェクトストレージバケット
- **IAM_Role**: AWS Identity and Access Managementのロール(権限セット)
- **Instance_Profile**: EC2インスタンスにIAMロールをアタッチするためのコンテナ
- **Security_Group**: EC2インスタンスのファイアウォールルール
- **Template**: CloudFormationテンプレート(YAML/JSON形式のインフラ定義ファイル)
- **Valid_Template**: CloudFormationの構文とスキーマに準拠したテンプレート
- **VPC**: Amazon Virtual Private Cloud(仮想プライベートネットワーク)
- **Subnet**: VPC内のIPアドレス範囲のセグメント
- **VPC_Endpoint**: VPCとAWSサービス間のプライベート接続
## 要件
### 要件1: CloudFormationテンプレートの作成
**ユーザーストーリー:** 開発者として、インフラストラクチャをコードとして定義できるように、CloudFormationテンプレートを作成したい
#### 受入基準
1. Template は、設定可能なインスタンスタイプを持つ EC2_Instance リソースを定義しなければならない
2. Template は、適切な命名規則を持つ S3_Bucket リソースを定義しなければならない
3. Template は、S3アクセス権限を持つ IAM_Role を定義しなければならない
4. Template は、IAM_Role を EC2_Instance に関連付ける Instance_Profile を定義しなければならない
5. Template は、EC2_Instance 用の Security_Group を定義しなければならない
6. Template は、VPC リソースを定義しなければならない
7. Template は、Subnet リソースを定義しなければならない
8. Template は、S3 用の VPC_Endpoint リソースを定義しなければならない
9. Template は、可読性のために YAML 形式を使用しなければならない
10. Template は、カスタマイズ可能な値(インスタンスタイプ、ランダムサフィックス)のためのパラメータを含まなければならない
11. Template は、作成されたリソース識別子のための出力を含まなければならない
12. Template は、S3以外のすべてのリソースに「Dev-AWSサービス-用途-連番」の形式で Name タグを付与しなければならない
13. Template は、S3バケットのみ「Dev-AWSサービス-用途-連番-ランダム8桁」の形式で Name タグを付与しなければならない
### 要件2: EC2インスタンスの設定
**ユーザーストーリー:** 開発者として、S3バケットにアクセスできるEC2インスタンスを自動的にプロビジョニングしたい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、EC2_Instance は指定されたインスタンスタイプで起動されなければならない
2. EC2_Instance が起動されたとき、System は S3 アクセスを有効にするために Instance_Profile をアタッチしなければならない
3. EC2_Instance が起動されたとき、System は Security_Group をインスタンスに関連付けなければならない
4. EC2_Instance は最新の Amazon Linux 2023 AMI を使用しなければならない
5. EC2_Instance は、AWS Systems Manager Session Manager を使用してアクセス可能でなければならない
6. EC2_Instance は、パブリック IP アドレスを持たないように設定されなければならない
### 要件3: S3バケットの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスからアクセス可能なS3バケットを作成したい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、S3_Bucket は命名規則に従った一意の名前で作成されなければならない
2. S3_Bucket は、データ保護のためにバージョニングを有効にしなければならない
3. S3_Bucket は、デフォルトでサーバー側暗号化を有効にしなければならない
4. S3_Bucket は、デフォルトでパブリックアクセスをブロックしなければならない
5. CloudFormation_Stack が削除されたとき、S3_Bucket はデータ損失を防ぐために保持されなければならない
### 要件4: IAMロールと権限の設定
**ユーザーストーリー:** 開発者として、EC2インスタンスがS3バケットとAWS Systems Managerに安全にアクセスできるように、適切な権限を設定したい
#### 受入基準
1. IAM_Role は、EC2_Instance に作成された S3_Bucket 内のオブジェクトをリストする権限を付与しなければならない
2. IAM_Role は、EC2_Instance に作成された S3_Bucket からオブジェクトを読み取る権限を付与しなければならない
3. IAM_Role は、EC2_Instance に作成された S3_Bucket へオブジェクトを書き込む権限を付与しなければならない
4. IAM_Role は、EC2_Instance に AWS Systems Manager Session Manager を使用するための権限を付与しなければならない
5. IAM_Role は、EC2_Instance に AWS Systems Manager のコア機能(SSM Agent通信、セッション管理)へのアクセス権限を付与しなければならない
6. IAM_Role は、最小権限の原則に従わなければならない(作成された S3_Bucket と必要な Systems Manager 機能のみへのアクセス)
7. IAM_Role は、EC2 サービスがロールを引き受けることを許可する信頼ポリシーを持たなければならない
### 要件5: セキュリティグループの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスへの安全なアクセスを制御したい
#### 受入基準
1. Security_Group は、AWS Systems Manager Session Manager を使用するため、インバウンド通信の許可を必要としない
2. Security_Group は、S3 アクセスを有効にするためにすべてのアウトバウンドトラフィックを許可しなければならない
3. Security_Group は、各ルールの説明を含まなければならない
### 要件6: スタックのデプロイと管理
**ユーザーストーリー:** 開発者として、CloudFormationスタックを簡単にデプロイ、更新、削除できるようにしたい
#### 受入基準
1. Valid_Template が CloudFormation に提供されたとき、System は定義されたすべてのリソースを作成しなければならない
2. CloudFormation_Stack の作成が失敗したとき、System は作成されたすべてのリソースをロールバックしなければならない
3. CloudFormation_Stack が Valid_Template で更新されたとき、System は変更されたリソースのみを変更しなければならない
4. CloudFormation_Stack が削除されたとき、System は保持ポリシーを持つリソースを除くすべてのリソースを削除しなければならない
5. Template は、CloudFormation 検証ツールを使用して正常に検証されなければならない
### 要件7: 出力とリソース情報
**ユーザーストーリー:** 開発者として、作成されたリソースの情報を簡単に取得したい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、System は EC2_Instance ID を出力しなければならない
2. CloudFormation_Stack が作成されたとき、System は S3_Bucket 名を出力しなければならない
3. CloudFormation_Stack が作成されたとき、System は IAM_Role ARN を出力しなければならない
4. 出力は、CloudFormation コンソールと CLI を通じてアクセス可能でなければならない
### 要件8: テンプレートの検証
**ユーザーストーリー:** 開発者として、テンプレートが正しい構文とベストプラクティスに従っていることを確認したい
#### 受入基準
1. Template は、CloudFormation スキーマに従って有効でなければならない
2. Template は、すべての必須リソースプロパティを含まなければならない
3. Template は、組み込み関数(Ref、GetAtt、Sub など)を正しく使用しなければならない
4. Template は、必要に応じてリソース間の依存関係を定義しなければならない
5. Template が AWS CLI を使用して検証されたとき、System はエラーなしで成功を返さなければならない
### 要件9: VPCとネットワークの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスを隔離されたネットワーク環境で実行したい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、VPC は指定された CIDR ブロックで作成されなければならない
2. VPC は、DNS 解決を有効にしなければならない
3. VPC は、DNS ホスト名を有効にしなければならない
4. CloudFormation_Stack が作成されたとき、Subnet は VPC 内に作成されなければならない
5. Subnet は、プライベートサブネットとして設定されなければならない(パブリックIPの自動割り当てなし)
6. EC2_Instance は、作成された Subnet 内に配置されなければならない
### 要件10: VPCエンドポイントの設定
**ユーザーストーリー:** 開発者として、EC2インスタンスがインターネットを経由せずにS3とSystems Managerにアクセスできるようにしたい
#### 受入基準
1. CloudFormation_Stack が作成されたとき、S3 用の VPC_Endpoint が作成されなければならない
2. S3用 VPC_Endpoint は、Gateway タイプでなければならない
3. VPC_Endpoint は、作成された VPC に関連付けられなければならない
4. S3用 VPC_Endpoint は、Subnet のルートテーブルに自動的に関連付けられなければならない
5. EC2_Instance から S3_Bucket への通信は、VPC_Endpoint を経由しなければならない
6. CloudFormation_Stack が作成されたとき、Systems Manager 用の VPC_Endpoint が作成されなければならない
7. Systems Manager用 VPC_Endpoint は、Interface タイプでなければならない
8. Systems Manager用 VPC_Endpoint は、以下の2つのエンドポイントを含まなければならない
   - com.amazonaws.{region}.ssm
   - com.amazonaws.{region}.ssmmessages
9. Systems Manager用 VPC_Endpoint は、プライベート DNS を有効にしなければならない
10. Systems Manager用 VPC_Endpoint は、専用のセキュリティグループで保護されなければならない
11. VPC_Endpoint 用セキュリティグループは、EC2インスタンスからのHTTPS通信(ポート443)のみを許可しなければならない

続いて、Kiro に「設計フェーズ」に進むと伝えます。

設計

設計フェーズに進むと、CloudFormation テンプレートの詳細設計を記載した「design.md」を作成してくれました。

最初に作成された「design.md」は以下の内容です。

design.md

# 設計書
## 概要
本設計書は、CloudFormationを使用してEC2インスタンスとS3バケットを作成し、安全な通信を確立するインフラストラクチャ自動化システムの詳細設計を定義します。このシステムは、YAML形式のCloudFormationテンプレートを使用して、AWS環境に以下のリソースを自動的にプロビジョニングします:
- EC2インスタンス(Amazon Linux 2023)
- S3バケット(暗号化とバージョニング有効)
- IAMロールとインスタンスプロファイル(S3とSystems Managerへのアクセス)
- セキュリティグループ(アウトバウンド通信のみ)
設計の主要な特徴:
- インフラストラクチャをコードとして管理(IaC)
- 最小権限の原則に基づくセキュリティ設計
- AWS Systems Manager Session Managerによる安全なアクセス
- パブリックIPなしのプライベートインスタンス
- 統一された命名規則(Dev-サービス名-用途-連番)
## アーキテクチャ
### システム構成図
```mermaid
graph TB
    subgraph "CloudFormation Stack"
        CFN[CloudFormation Template
YAML] end subgraph "Compute Layer" EC2[EC2 Instance
Amazon Linux 2023
No Public IP] SG[Security Group
Outbound Only] end subgraph "Storage Layer" S3[S3 Bucket
Versioning + Encryption] end subgraph "Identity & Access" IAM[IAM Role] IP[Instance Profile] end subgraph "Management" SSM[Systems Manager
Session Manager] end CFN -->|Creates| EC2 CFN -->|Creates| S3 CFN -->|Creates| IAM CFN -->|Creates| IP CFN -->|Creates| SG EC2 -.->|Attached| IP IP -.->|Assumes| IAM EC2 -.->|Associated| SG EC2 -->|Read/Write| S3 EC2 -->|Managed by| SSM IAM -->|Grants Access| S3 IAM -->|Grants Access| SSM style CFN fill:#ff9900 style EC2 fill:#ec7211 style S3 fill:#569a31 style IAM fill:#dd344c style SSM fill:#527fff ``` ### リソース依存関係 ```mermaid graph LR IAM[IAM Role] --> IP[Instance Profile] IP --> EC2[EC2 Instance] SG[Security Group] --> EC2 S3[S3 Bucket] style IAM fill:#dd344c style IP fill:#dd344c style EC2 fill:#ec7211 style SG fill:#ec7211 style S3 fill:#569a31 ``` 依存関係の説明: 1. IAMロールが最初に作成される 2. インスタンスプロファイルがIAMロールを参照して作成される 3. セキュリティグループが作成される 4. EC2インスタンスがインスタンスプロファイルとセキュリティグループを参照して作成される 5. S3バケットは独立して作成される(他のリソースへの依存なし) ## コンポーネントとインターフェース ### 1. CloudFormationテンプレート **責務**: すべてのAWSリソースの定義と設定 **構造**: ```yaml AWSTemplateFormatVersion: '2010-09-09' Description: 'EC2とS3の通信環境を構築するテンプレート' Parameters: # カスタマイズ可能なパラメータ Resources: # リソース定義 Outputs: # 出力値 ``` **パラメータ**: - `InstanceType`: EC2インスタンスタイプ(デフォルト: t3.micro) - `BucketNamePrefix`: S3バケット名のプレフィックス - `EnvironmentName`: 環境名(Nameタグに使用) ### 2. EC2インスタンス **リソースタイプ**: `AWS::EC2::Instance` **主要プロパティ**: ```yaml Type: AWS::EC2::Instance Properties: ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}' InstanceType: !Ref InstanceType IamInstanceProfile: !Ref InstanceProfile SecurityGroupIds: - !Ref SecurityGroup NetworkInterfaces: - AssociatePublicIpAddress: false DeviceIndex: 0 Tags: - Key: Name Value: !Sub 'Dev-${EnvironmentName}-EC2-001' ``` **特徴**: - 最新のAmazon Linux 2023 AMIを動的に取得(SSMパラメータストア使用) - パブリックIPアドレスなし - インスタンスプロファイル経由でIAMロールをアタッチ - 統一された命名規則のNameタグ ### 3. S3バケット **リソースタイプ**: `AWS::S3::Bucket` **主要プロパティ**: ```yaml Type: AWS::S3::Bucket Properties: BucketName: !Sub '${BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}' VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true Tags: - Key: Name Value: !Sub 'Dev-${EnvironmentName}-S3-001' DeletionPolicy: Retain UpdateReplacePolicy: Retain ``` **特徴**: - アカウントIDとリージョンを含む一意の名前 - バージョニング有効化 - AES256によるサーバー側暗号化 - すべてのパブリックアクセスをブロック - スタック削除時も保持(データ保護) ### 4. IAMロール **リソースタイプ**: `AWS::IAM::Role` **信頼ポリシー**: ```yaml AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: 'sts:AssumeRole' ``` **S3アクセスポリシー**: ```yaml Policies: - PolicyName: S3AccessPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 's3:ListBucket' Resource: !GetAtt S3Bucket.Arn - Effect: Allow Action: - 's3:GetObject' - 's3:PutObject' Resource: !Sub '${S3Bucket.Arn}/*' ``` **Systems Managerアクセスポリシー**: ```yaml ManagedPolicyArns: - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore' ``` **特徴**: - EC2サービスのみがロールを引き受け可能 - 作成されたS3バケットのみへのアクセス(最小権限) - AWSマネージドポリシーでSystems Manager機能を有効化 - 統一された命名規則 ### 5. インスタンスプロファイル **リソースタイプ**: `AWS::IAM::InstanceProfile` **主要プロパティ**: ```yaml Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref IAMRole InstanceProfileName: !Sub 'Dev-${EnvironmentName}-InstanceProfile-001' ``` **特徴**: - IAMロールをEC2インスタンスにアタッチするためのコンテナ - 1つのロールのみを含む ### 6. セキュリティグループ **リソースタイプ**: `AWS::EC2::SecurityGroup` **主要プロパティ**: ```yaml Type: AWS::EC2::SecurityGroup Properties: GroupDescription: 'Security group for EC2 instance with S3 access' SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 Description: 'Allow all outbound traffic for S3 and Systems Manager access' Tags: - Key: Name Value: !Sub 'Dev-${EnvironmentName}-SG-001' ``` **特徴**: - インバウンドルールなし(Session Manager使用のため) - すべてのアウトバウンドトラフィックを許可 - 各ルールに説明を含む ### 7. 出力 **主要な出力値**: ```yaml Outputs: InstanceId: Description: 'EC2 Instance ID' Value: !Ref EC2Instance Export: Name: !Sub '${AWS::StackName}-InstanceId' BucketName: Description: 'S3 Bucket Name' Value: !Ref S3Bucket Export: Name: !Sub '${AWS::StackName}-BucketName' IAMRoleArn: Description: 'IAM Role ARN' Value: !GetAtt IAMRole.Arn Export: Name: !Sub '${AWS::StackName}-IAMRoleArn' ``` **特徴**: - 他のスタックから参照可能(Export使用) - スタック名をプレフィックスとして使用 ## データモデル ### パラメータデータ構造 ```yaml Parameters: InstanceType: Type: String Default: t3.micro AllowedValues: - t3.micro - t3.small - t3.medium Description: 'EC2インスタンスタイプ' BucketNamePrefix: Type: String Default: 'dev-app-data' AllowedPattern: '^[a-z0-9][a-z0-9-]*[a-z0-9]$' MinLength: 3 MaxLength: 37 Description: 'S3バケット名のプレフィックス(小文字英数字とハイフンのみ)' EnvironmentName: Type: String Default: 'App' Description: 'リソースのNameタグに使用する環境名' ``` ### リソース命名規則 すべてのリソースは以下の形式でNameタグを持つ: ``` Dev-{EnvironmentName}-{ResourceType}-{SequenceNumber} ``` 例: - EC2インスタンス: `Dev-App-EC2-001` - S3バケット: `Dev-App-S3-001` - セキュリティグループ: `Dev-App-SG-001` - IAMロール: `Dev-App-Role-001` ### S3バケット命名規則 S3バケット名は以下の形式: ``` {BucketNamePrefix}-{AccountId}-{Region} ``` 例: `dev-app-data-123456789012-ap-northeast-1` この形式により: - グローバルに一意な名前を保証 - アカウントとリージョンの識別が容易 - 複数環境での衝突を回避 ## 正確性プロパティ プロパティとは、システムのすべての有効な実行において真であるべき特性や動作のことです。プロパティは、人間が読める仕様と機械で検証可能な正確性保証の橋渡しとなります。 ### テンプレート構造プロパティ **プロパティ1: EC2インスタンスリソースの定義** *任意の*有効なCloudFormationテンプレートにおいて、EC2インスタンスリソースが存在し、InstanceTypeプロパティがパラメータ参照を含む場合、そのテンプレートは設定可能なインスタンスタイプを持つ **検証: 要件 1.1** **プロパティ2: S3バケットリソースの定義** *任意の*有効なCloudFormationテンプレートにおいて、S3バケットリソースが存在し、BucketNameプロパティがアカウントIDまたはリージョンを含む場合、そのテンプレートは適切な命名規則を持つ **検証: 要件 1.2, 3.1** **プロパティ3: IAMロールリソースの定義** *任意の*有効なCloudFormationテンプレートにおいて、IAMロールリソースが存在し、S3アクセス権限(ListBucket、GetObject、PutObject)を含むポリシーを持つ場合、そのテンプレートはS3アクセス権限を持つIAMロールを定義する **検証: 要件 1.3, 4.1, 4.2, 4.3** **プロパティ4: インスタンスプロファイルリソースの定義** *任意の*有効なCloudFormationテンプレートにおいて、インスタンスプロファイルリソースが存在し、IAMロールを参照している場合、そのテンプレートはIAMロールをEC2インスタンスに関連付けるインスタンスプロファイルを定義する **検証: 要件 1.4** **プロパティ5: セキュリティグループリソースの定義** *任意の*有効なCloudFormationテンプレートにおいて、セキュリティグループリソースが存在する場合、そのテンプレートはEC2インスタンス用のセキュリティグループを定義する **検証: 要件 1.5** **プロパティ6: パラメータの定義** *任意の*有効なCloudFormationテンプレートにおいて、Parametersセクションに「InstanceType」と「BucketNamePrefix」が含まれる場合、そのテンプレートはカスタマイズ可能な値のためのパラメータを含む **検証: 要件 1.7** **プロパティ7: 出力の定義** *任意の*有効なCloudFormationテンプレートにおいて、Outputsセクションに「InstanceId」、「BucketName」、「IAMRoleArn」が含まれる場合、そのテンプレートは作成されたリソース識別子のための出力を含む **検証: 要件 1.8, 7.1, 7.2, 7.3** **プロパティ8: Nameタグの命名規則** *任意の*有効なCloudFormationテンプレートにおいて、すべてのリソースがNameタグを持ち、その値が「Dev-{EnvironmentName}-{ResourceType}-{SequenceNumber}」の形式に従う場合、そのテンプレートは統一された命名規則を持つ **検証: 要件 1.9** ### EC2インスタンス設定プロパティ **プロパティ9: インスタンスプロファイルのアタッチ** *任意の*有効なCloudFormationテンプレートにおいて、EC2インスタンスリソースがIamInstanceProfileプロパティを持ち、インスタンスプロファイルを参照している場合、そのインスタンスはS3アクセスを有効にするためのインスタンスプロファイルをアタッチする **検証: 要件 2.2** **プロパティ10: セキュリティグループの関連付け** *任意の*有効なCloudFormationテンプレートにおいて、EC2インスタンスリソースがSecurityGroupIdsプロパティを持ち、セキュリティグループを参照している場合、そのインスタンスはセキュリティグループを関連付ける **検証: 要件 2.3** **プロパティ11: Amazon Linux 2023 AMIの使用** *任意の*有効なCloudFormationテンプレートにおいて、EC2インスタンスのImageIdプロパティが「al2023-ami-kernel-default」を含むSSMパラメータを参照している場合、そのインスタンスは最新のAmazon Linux 2023 AMIを使用する **検証: 要件 2.4** **プロパティ12: Systems Managerアクセスの有効化** *任意の*有効なCloudFormationテンプレートにおいて、IAMロールが「AmazonSSMManagedInstanceCore」マネージドポリシーをアタッチしている場合、EC2インスタンスはAWS Systems Manager Session Managerを使用してアクセス可能である **検証: 要件 2.5, 4.4, 4.5** **プロパティ13: パブリックIPアドレスの無効化** *任意の*有効なCloudFormationテンプレートにおいて、EC2インスタンスのNetworkInterfacesでAssociatePublicIpAddressがfalseに設定されている場合、そのインスタンスはパブリックIPアドレスを持たない **検証: 要件 2.6** ### S3バケット設定プロパティ **プロパティ14: バージョニングの有効化** *任意の*有効なCloudFormationテンプレートにおいて、S3バケットのVersioningConfigurationのStatusが「Enabled」に設定されている場合、そのバケットはデータ保護のためにバージョニングを有効にする **検証: 要件 3.2** **プロパティ15: サーバー側暗号化の有効化** *任意の*有効なCloudFormationテンプレートにおいて、S3バケットのBucketEncryptionが設定され、SSEAlgorithmが指定されている場合、そのバケットはデフォルトでサーバー側暗号化を有効にする **検証: 要件 3.3** **プロパティ16: パブリックアクセスのブロック** *任意の*有効なCloudFormationテンプレートにおいて、S3バケットのPublicAccessBlockConfigurationのすべてのプロパティ(BlockPublicAcls、BlockPublicPolicy、IgnorePublicAcls、RestrictPublicBuckets)がtrueに設定されている場合、そのバケットはデフォルトでパブリックアクセスをブロックする **検証: 要件 3.4** **プロパティ17: バケットの保持ポリシー** *任意の*有効なCloudFormationテンプレートにおいて、S3バケットのDeletionPolicyが「Retain」に設定されている場合、スタック削除時にそのバケットはデータ損失を防ぐために保持される **検証: 要件 3.5** ### IAMロールと権限プロパティ **プロパティ18: 最小権限の原則(S3アクセス)** *任意の*有効なCloudFormationテンプレートにおいて、IAMロールのS3ポリシーのResourceプロパティが特定のバケットARNのみを参照している場合、そのロールは最小権限の原則に従う **検証: 要件 4.6** **プロパティ19: EC2信頼ポリシー** *任意の*有効なCloudFormationテンプレートにおいて、IAMロールのAssumeRolePolicyDocumentのPrincipalに「ec2.amazonaws.com」が含まれる場合、そのロールはEC2サービスがロールを引き受けることを許可する **検証: 要件 4.7** ### セキュリティグループプロパティ **プロパティ20: インバウンドルールの不在** *任意の*有効なCloudFormationテンプレートにおいて、セキュリティグループのSecurityGroupIngressが定義されていないか空である場合、そのセキュリティグループはAWS Systems Manager Session Managerを使用するためインバウンド通信の許可を必要としない **検証: 要件 5.1** **プロパティ21: アウトバウンドトラフィックの許可** *任意の*有効なCloudFormationテンプレートにおいて、セキュリティグループのSecurityGroupEgressにIpProtocol「-1」とCidrIp「0.0.0.0/0」を含むルールが存在する場合、そのセキュリティグループはすべてのアウトバウンドトラフィックを許可する **検証: 要件 5.2** **プロパティ22: セキュリティグループルールの説明** *任意の*有効なCloudFormationテンプレートにおいて、すべてのセキュリティグループルール(IngressとEgress)がDescriptionプロパティを持つ場合、そのセキュリティグループは各ルールの説明を含む **検証: 要件 5.3** ### テンプレート検証プロパティ **プロパティ23: CloudFormation検証のラウンドトリップ** *任意の*CloudFormationテンプレートファイルにおいて、AWS CLIの「validate-template」コマンドを実行したとき、エラーなしで成功を返す場合、そのテンプレートはCloudFormationスキーマに従って有効であり、すべての必須プロパティを含み、組み込み関数を正しく使用している **検証: 要件 6.5, 8.1, 8.2, 8.3, 8.5** **プロパティ24: リソース間依存関係の定義** *任意の*有効なCloudFormationテンプレートにおいて、EC2インスタンスがインスタンスプロファイルとセキュリティグループを参照し、インスタンスプロファイルがIAMロールを参照している場合、そのテンプレートは必要なリソース間の依存関係を定義する **検証: 要件 8.4** ## エラーハンドリング ### テンプレート検証エラー **エラーケース**: テンプレートがCloudFormationスキーマに準拠していない **処理**: - AWS CLIの`validate-template`コマンドを使用して事前検証 - エラーメッセージを解析して具体的な問題を特定 - 修正後に再検証 **例**: ```bash aws cloudformation validate-template --template-body file://template.yaml ``` ### パラメータ検証エラー **エラーケース**: 無効なパラメータ値が提供された **処理**: - AllowedValuesとAllowedPatternによる制約 - MinLength/MaxLengthによる長さ制限 - CloudFormationが自動的に検証し、エラーを返す **例**: ```yaml Parameters: BucketNamePrefix: Type: String AllowedPattern: '^[a-z0-9][a-z0-9-]*[a-z0-9]$' ConstraintDescription: 'バケット名は小文字英数字とハイフンのみを含む必要があります' ``` ### リソース作成エラー **エラーケース**: リソース作成中にエラーが発生 **処理**: - CloudFormationの自動ロールバック機能 - スタックイベントログでエラー原因を確認 - 必要に応じてテンプレートを修正して再デプロイ **例**: - S3バケット名の重複 - IAM権限の不足 - リソース制限の超過 ### 依存関係エラー **エラーケース**: リソース間の依存関係が正しく解決されない **処理**: - CloudFormationが自動的に依存関係を解決 - 明示的な`DependsOn`属性が必要な場合は追加 - リソース参照(Ref、GetAtt)により暗黙的な依存関係を確立 **例**: ```yaml EC2Instance: Type: AWS::EC2::Instance Properties: IamInstanceProfile: !Ref InstanceProfile # 暗黙的な依存関係 ``` ### スタック削除エラー **エラーケース**: S3バケットが空でないためスタック削除が失敗 **処理**: - DeletionPolicy: Retainにより、スタック削除時にバケットを保持 - 手動でバケットを空にしてから削除 - または、バケットを保持したままスタックのみ削除 ## テスト戦略 ### デュアルテストアプローチ 本プロジェクトでは、ユニットテストとプロパティベーステストの両方を使用して包括的なカバレッジを実現します: - **ユニットテスト**: 特定の例、エッジケース、エラー条件を検証 - **プロパティテスト**: すべての入力にわたる普遍的なプロパティを検証 両方のアプローチは補完的であり、包括的なカバレッジに必要です。 ### ユニットテストのバランス ユニットテストは特定の例とエッジケースに役立ちますが、プロパティベーステストが多くの入力をカバーするため、過度に多くのユニットテストを書くことは避けます。 **ユニットテストの焦点**: - テンプレートが正しくパースできることの確認 - 特定のリソースタイプの存在確認 - エッジケース(空のパラメータ、無効な値など) - コンポーネント間の統合ポイント **プロパティテストの焦点**: - すべての入力に対して保持される普遍的なプロパティ - ランダム化による包括的な入力カバレッジ ### プロパティベーステスト設定 **使用ライブラリ**: Python用の`hypothesis` **設定**: - 各プロパティテストは最低100回の反復を実行 - 各テストは設計ドキュメントのプロパティを参照 - タグ形式: **Feature: ec2-s3-cloudformation, Property {番号}: {プロパティテキスト}** **例**: ```python from hypothesis import given, strategies as st import yaml @given(st.text()) def test_property_1_ec2_instance_definition(template_content): """ Feature: ec2-s3-cloudformation, Property 1: EC2インスタンスリソースの定義 任意の有効なCloudFormationテンプレートにおいて、EC2インスタンスリソースが存在し、 InstanceTypeプロパティがパラメータ参照を含む場合、 そのテンプレートは設定可能なインスタンスタイプを持つ """ try: template = yaml.safe_load(template_content) if 'Resources' in template: for resource_name, resource in template['Resources'].items(): if resource.get('Type') == 'AWS::EC2::Instance': instance_type = resource.get('Properties', {}).get('InstanceType') if isinstance(instance_type, dict) and 'Ref' in instance_type: assert True # プロパティが満たされている return except: pass # 無効なテンプレートはスキップ ``` ### テストカテゴリ #### 1. テンプレート構造テスト **目的**: テンプレートが必要なリソースとプロパティを含むことを確認 **アプローチ**: - YAMLパーサーを使用してテンプレートを読み込み - 各リソースタイプの存在を確認 - 必須プロパティの存在を確認 **例**: ```python def test_template_contains_ec2_instance(): """EC2インスタンスリソースが存在することを確認""" with open('template.yaml') as f: template = yaml.safe_load(f) ec2_resources = [r for r in template['Resources'].values() if r['Type'] == 'AWS::EC2::Instance'] assert len(ec2_resources) == 1 ``` #### 2. CloudFormation検証テスト **目的**: テンプレートがCloudFormationスキーマに準拠することを確認 **アプローチ**: - AWS CLIの`validate-template`コマンドを実行 - 成功ステータスを確認 **例**: ```python def test_template_validates_with_cloudformation(): """テンプレートがCloudFormation検証を通過することを確認""" result = subprocess.run( ['aws', 'cloudformation', 'validate-template', '--template-body', 'file://template.yaml'], capture_output=True ) assert result.returncode == 0 ``` #### 3. セキュリティ設定テスト **目的**: セキュリティベストプラクティスが実装されていることを確認 **アプローチ**: - S3バケットの暗号化設定を確認 - パブリックアクセスブロック設定を確認 - IAMロールの最小権限を確認 **例**: ```python def test_s3_bucket_encryption_enabled(): """S3バケットで暗号化が有効であることを確認""" with open('template.yaml') as f: template = yaml.safe_load(f) s3_buckets = [r for r in template['Resources'].values() if r['Type'] == 'AWS::S3::Bucket'] for bucket in s3_buckets: assert 'BucketEncryption' in bucket['Properties'] ``` #### 4. 命名規則テスト **目的**: すべてのリソースが統一された命名規則に従うことを確認 **アプローチ**: - すべてのリソースのNameタグを確認 - 正規表現で形式を検証 **例**: ```python import re def test_resource_naming_convention(): """すべてのリソースが命名規則に従うことを確認""" with open('template.yaml') as f: template = yaml.safe_load(f) pattern = re.compile(r'^Dev-\w+-\w+-\d{3}$') for resource in template['Resources'].values(): tags = resource.get('Properties', {}).get('Tags', []) name_tag = next((t for t in tags if t['Key'] == 'Name'), None) if name_tag: # Subを含む場合は評価をスキップ if not isinstance(name_tag['Value'], dict): assert pattern.match(name_tag['Value']) ``` ### 統合テスト(オプション) 実際のAWS環境でのテストは、このプロジェクトの範囲外ですが、以下のアプローチが推奨されます: 1. **テスト環境でのスタック作成** - CloudFormationスタックを作成 - すべてのリソースが正常に作成されることを確認 2. **機能テスト** - EC2インスタンスにSession Manager経由で接続 - S3バケットへの読み書きをテスト 3. **クリーンアップ** - テストスタックを削除 - S3バケットが保持されることを確認 ### テスト実行 ```bash # ユニットテストの実行 pytest tests/unit/ # プロパティベーステストの実行(100回の反復) pytest tests/property/ --hypothesis-seed=random # すべてのテストの実行 pytest tests/ # カバレッジレポート pytest --cov=. --cov-report=html ```

設計書には Mermaid による構成図や、CloudFormation テンプレートの要素ごとの説明が記載され、人が読むことも意識されています。
一方で、Kiro の Spec ファイルとして要件の網羅性を優先しているためか、ドキュメントが長く冗長に感じる部分もありました。

開発完了時点の「design.md」は次の内容になりました。
(筆者の環境都合で、システム構成図は Mermaid から Markdown に変更してもらいました)

design.md

# 設計書
## 概要
本設計書は、CloudFormationを使用してEC2インスタンスとS3バケットを作成し、安全な通信を確立するインフラストラクチャ自動化システムの詳細設計を定義します。このシステムは、YAML形式のCloudFormationテンプレートを使用して、AWS環境に以下のリソースを自動的にプロビジョニングします:
- EC2インスタンス(Amazon Linux 2023)
- S3バケット(暗号化とバージョニング有効)
- IAMロールとインスタンスプロファイル(S3とSystems Managerへのアクセス)
- セキュリティグループ(アウトバウンド通信のみ)
設計の主要な特徴:
- インフラストラクチャをコードとして管理(IaC)
- 最小権限の原則に基づくセキュリティ設計
- AWS Systems Manager Session Managerによる安全なアクセス
- パブリックIPなしのプライベートインスタンス
- 統一された命名規則(Dev-サービス名-用途-連番)
## アーキテクチャ
### システム構成
本システムは以下のレイヤーで構成されます:
#### 1. インフラストラクチャ定義レイヤー
- **CloudFormation Template (YAML)**
  - すべてのAWSリソースを定義
  - パラメータによるカスタマイズ可能
  - 出力によるリソース情報の提供
#### 2. コンピューティングレイヤー
- **EC2 Instance**
  - Amazon Linux 2023
  - パブリックIPなし(プライベートインスタンス)
  - インスタンスプロファイル経由でIAMロールをアタッチ
  - セキュリティグループで保護
- **Security Group**
  - インバウンドルールなし
  - アウトバウンドトラフィックのみ許可
#### 3. ストレージレイヤー
- **S3 Bucket**
  - バージョニング有効
  - サーバー側暗号化(AES256)
  - パブリックアクセスブロック
  - スタック削除時も保持
#### 4. アイデンティティとアクセス管理レイヤー
- **IAM Role**
  - S3バケットへのアクセス権限(List、Get、Put)
  - Systems Managerへのアクセス権限
  - EC2サービスによる引き受けを許可
- **Instance Profile**
  - IAMロールをEC2インスタンスにアタッチ
#### 5. ネットワークレイヤー
- **VPC (Virtual Private Cloud)**
  - 隔離されたプライベートネットワーク
  - DNS解決とDNSホスト名を有効化
  - カスタムCIDRブロック
- **Subnet**
  - VPC内のプライベートサブネット
  - パブリックIPの自動割り当てなし
  - EC2インスタンスを配置
- **VPC Endpoint (S3 Gateway)**
  - S3へのプライベート接続
  - インターネットゲートウェイ不要
  - ルートテーブルに自動統合
- **VPC Endpoints (SSM Interface)**
  - Systems Manager用のInterface型エンドポイント
  - プライベートサブネットからSSM Session Managerへのアクセスを提供
  - 2つのエンドポイント: ssm, ssmmessages
  - 専用のセキュリティグループで保護
#### 6. 管理レイヤー
- **Systems Manager Session Manager**
  - EC2インスタンスへの安全なアクセス
  - SSHキーやパブリックIPなしでアクセス可能
### リソース間の関係
```
CloudFormation Template
├── 作成 → VPC
├── 作成 → Subnet (VPCを参照)
├── 作成 → Route Table (VPCを参照)
├── 作成 → VPC Endpoint for S3 (VPCとRoute Tableを参照)
├── 作成 → VPC Endpoint Security Group (VPCを参照)
├── 作成 → SSM VPC Endpoints (VPC、Subnet、Security Groupを参照)
│   ├── com.amazonaws.region.ssm
│   └── com.amazonaws.region.ssmmessages
├── 作成 → IAM Role
├── 作成 → Instance Profile (IAM Roleを参照)
├── 作成 → Security Group (VPCを参照)
├── 作成 → EC2 Instance (Subnet、Instance Profile、Security Groupを参照)
└── 作成 → S3 Bucket (独立)
EC2 Instance
├── 配置 → Subnet (VPC内)
├── アタッチ → Instance Profile
│   └── 引き受け → IAM Role
│       ├── アクセス許可 → S3 Bucket
│       └── アクセス許可 → Systems Manager
├── 関連付け → Security Group
├── 通信 → VPC Endpoint → S3 Bucket (プライベート接続)
└── 管理 → SSM VPC Endpoints → Systems Manager Session Manager
```
### リソース依存関係
リソースの作成順序:
1. **VPC** (最初に作成)
   - 他のリソースへの依存なし
2. **Subnet** (VPCの後)
   - VPCを参照
3. **Route Table** (VPCの後)
   - VPCを参照
   - Subnetに関連付け
4. **VPC Endpoint** (VPCとRoute Tableの後)
   - VPCを参照
   - Route Tableを参照
5. **VPC Endpoint Security Group** (VPCの後)
   - VPCを参照
   - EC2インスタンスのSecurity Groupを参照
6. **SSM VPC Endpoints** (VPC、Subnet、VPC Endpoint Security Groupの後)
   - VPCを参照
   - Subnetを参照
   - VPC Endpoint Security Groupを参照
7. **IAM Role** (独立して作成可能)
   - 他のリソースへの依存なし
8. **Instance Profile** (IAM Roleの後)
   - IAM Roleを参照
9. **Security Group** (VPCの後)
   - VPCを参照
10. **EC2 Instance** (Subnet、Instance Profile、Security Groupの後)
   - Subnetを参照
   - Instance Profileを参照
   - Security Groupを参照
11. **S3 Bucket** (独立して作成可能)
   - 他のリソースへの依存なし
CloudFormationは、リソース間の参照(Ref、GetAtt)を解析して、自動的に正しい順序でリソースを作成します。
## コンポーネントとインターフェース
### 1. CloudFormationテンプレート
**責務**: すべてのAWSリソースの定義と設定
**構造**:
```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'EC2とS3の通信環境を構築するテンプレート'
Parameters:
  # カスタマイズ可能なパラメータ
Resources:
  # リソース定義
Outputs:
  # 出力値
```
**パラメータ**:
- `InstanceType`: EC2インスタンスタイプ(デフォルト: t3.micro)
- `RandomSuffix`: リソース名の一意性を保証するランダムな8桁の数値
### 2. EC2インスタンス
**リソースタイプ**: `AWS::EC2::Instance`
**主要プロパティ**:
```yaml
Type: AWS::EC2::Instance
Properties:
  ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}'
  InstanceType: !Ref InstanceType
  IamInstanceProfile: !Ref InstanceProfile
  SubnetId: !Ref Subnet
  SecurityGroupIds:
    - !Ref SecurityGroup
  Tags:
    - Key: Name
      Value: 'Dev-EC2-Linux-01'
```
**特徴**:
- 最新のAmazon Linux 2023 AMIを動的に取得(SSMパラメータストア使用)
- プライベートサブネットに配置
- パブリックIPアドレスなし
- インスタンスプロファイル経由でIAMロールをアタッチ
- 統一された命名規則のNameタグ
### 3. S3バケット
**リソースタイプ**: `AWS::S3::Bucket`
**主要プロパティ**:
```yaml
Type: AWS::S3::Bucket
Properties:
  BucketName: !Sub 'dev-s3-data-01-${RandomSuffix}'
  VersioningConfiguration:
    Status: Enabled
  BucketEncryption:
    ServerSideEncryptionConfiguration:
      - ServerSideEncryptionByDefault:
          SSEAlgorithm: AES256
  PublicAccessBlockConfiguration:
    BlockPublicAcls: true
    BlockPublicPolicy: true
    IgnorePublicAcls: true
    RestrictPublicBuckets: true
  Tags:
    - Key: Name
      Value: !Sub 'Dev-S3-Data-01-${RandomSuffix}'
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
```
**特徴**:
- Nameタグと同じ形式のバケット名(小文字)
- ランダム8桁のサフィックスで一意性を保証
- バージョニング有効化
- AES256によるサーバー側暗号化
- すべてのパブリックアクセスをブロック
- スタック削除時も保持(データ保護)
**注意**: `RandomSuffix`パラメータは、テンプレートのParametersセクションで定義する必要があります。
### 4. IAMロール
**リソースタイプ**: `AWS::IAM::Role`
**信頼ポリシー**:
```yaml
AssumeRolePolicyDocument:
  Version: '2012-10-17'
  Statement:
    - Effect: Allow
      Principal:
        Service: ec2.amazonaws.com
      Action: 'sts:AssumeRole'
```
**S3アクセスポリシー**:
```yaml
Policies:
  - PolicyName: S3AccessPolicy
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Action:
            - 's3:ListBucket'
          Resource: !GetAtt S3Bucket.Arn
        - Effect: Allow
          Action:
            - 's3:GetObject'
            - 's3:PutObject'
          Resource: !Sub '${S3Bucket.Arn}/*'
```
**Systems Managerアクセスポリシー**:
```yaml
ManagedPolicyArns:
  - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
```
**特徴**:
- EC2サービスのみがロールを引き受け可能
- 作成されたS3バケットのみへのアクセス(最小権限)
- AWSマネージドポリシーでSystems Manager機能を有効化
- 統一された命名規則
### 5. インスタンスプロファイル
**リソースタイプ**: `AWS::IAM::InstanceProfile`
**主要プロパティ**:
```yaml
Type: AWS::IAM::InstanceProfile
Properties:
  Roles:
    - !Ref IAMRole
  InstanceProfileName: 'Dev-IAM-InstanceProfile-01'
```
**特徴**:
- IAMロールをEC2インスタンスにアタッチするためのコンテナ
- 1つのロールのみを含む
### 6. セキュリティグループ
**リソースタイプ**: `AWS::EC2::SecurityGroup`
**主要プロパティ**:
```yaml
Type: AWS::EC2::SecurityGroup
Properties:
  GroupDescription: 'Security group for EC2 instance with S3 access'
  VpcId: !Ref VPC
  SecurityGroupEgress:
    - IpProtocol: -1
      CidrIp: 0.0.0.0/0
      Description: 'Allow all outbound traffic for S3 and Systems Manager access'
  Tags:
    - Key: Name
      Value: 'Dev-SG-Web-01'
```
**特徴**:
- VPCに関連付け
- インバウンドルールなし(Session Manager使用のため)
- すべてのアウトバウンドトラフィックを許可
- 各ルールに説明を含む
### 7. 出力
**主要な出力値**:
```yaml
Outputs:
  InstanceId:
    Description: 'EC2 Instance ID'
    Value: !Ref EC2Instance
    Export:
      Name: !Sub '${AWS::StackName}-InstanceId'
  BucketName:
    Description: 'S3 Bucket Name'
    Value: !Ref S3Bucket
    Export:
      Name: !Sub '${AWS::StackName}-BucketName'
  IAMRoleArn:
    Description: 'IAM Role ARN'
    Value: !GetAtt IAMRole.Arn
    Export:
      Name: !Sub '${AWS::StackName}-IAMRoleArn'
```
**特徴**:
- 他のスタックから参照可能(Export使用)
- スタック名をプレフィックスとして使用
### 8. VPC
**リソースタイプ**: `AWS::EC2::VPC`
**主要プロパティ**:
```yaml
Type: AWS::EC2::VPC
Properties:
  CidrBlock: 10.0.0.0/16
  EnableDnsSupport: true
  EnableDnsHostnames: true
  Tags:
    - Key: Name
      Value: 'Dev-VPC-Main-01'
```
**特徴**:
- プライベートIPアドレス範囲(10.0.0.0/16)
- DNS解決とDNSホスト名を有効化
- 隔離されたネットワーク環境
### 9. Subnet
**リソースタイプ**: `AWS::EC2::Subnet`
**主要プロパティ**:
```yaml
Type: AWS::EC2::Subnet
Properties:
  VpcId: !Ref VPC
  CidrBlock: 10.0.1.0/24
  AvailabilityZone: !Select [0, !GetAZs '']
  MapPublicIpOnLaunch: false
  Tags:
    - Key: Name
      Value: 'Dev-Subnet-Private-01'
```
**特徴**:
- VPC内のプライベートサブネット
- パブリックIPの自動割り当てなし
- 最初のアベイラビリティゾーンに配置
- EC2インスタンスを配置
### 10. Route Table
**リソースタイプ**: `AWS::EC2::RouteTable`
**主要プロパティ**:
```yaml
Type: AWS::EC2::RouteTable
Properties:
  VpcId: !Ref VPC
  Tags:
    - Key: Name
      Value: 'Dev-RouteTable-Private-01'
```
**Subnet Association**:
```yaml
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
  SubnetId: !Ref Subnet
  RouteTableId: !Ref RouteTable
```
**特徴**:
- VPCに関連付け
- Subnetに関連付け
- VPCエンドポイントのルートを自動追加
### 11. VPC Endpoint (S3 Gateway)
**リソースタイプ**: `AWS::EC2::VPCEndpoint`
**主要プロパティ**:
```yaml
Type: AWS::EC2::VPCEndpoint
Properties:
  VpcId: !Ref VPC
  ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
  VpcEndpointType: Gateway
  RouteTableIds:
    - !Ref RouteTable
```
**特徴**:
- Gatewayタイプ(追加料金なし)
- S3サービスへのプライベート接続
- ルートテーブルに自動的にルートを追加
- インターネットゲートウェイ不要
- データ転送がAWSネットワーク内で完結
### 12. VPC Endpoint Security Group
**リソースタイプ**: `AWS::EC2::SecurityGroup`
**主要プロパティ**:
```yaml
Type: AWS::EC2::SecurityGroup
Properties:
  GroupName: 'Dev-SG-VPCEndpoint-01'
  GroupDescription: 'Security group for VPC Endpoints'
  VpcId: !Ref VPC
  SecurityGroupIngress:
    - IpProtocol: tcp
      FromPort: 443
      ToPort: 443
      SourceSecurityGroupId: !Ref SecurityGroup
      Description: 'Allow HTTPS from EC2 instances'
  Tags:
    - Key: Name
      Value: 'Dev-SG-VPCEndpoint-01'
```
**特徴**:
- Interface型VPCエンドポイント用のセキュリティグループ
- EC2インスタンスからのHTTPS通信(ポート443)のみ許可
- EC2インスタンスのセキュリティグループを送信元として指定
### 13. SSM VPC Endpoints (Interface型)
**リソースタイプ**: `AWS::EC2::VPCEndpoint`
**必要なエンドポイント**:
1. **SSM Endpoint**: Systems Managerサービスへのアクセス
2. **SSM Messages Endpoint**: Session Managerのメッセージング
**主要プロパティ**:
```yaml
SSMVPCEndpoint:
  Type: AWS::EC2::VPCEndpoint
  Properties:
    VpcId: !Ref VPC
    ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssm'
    VpcEndpointType: Interface
    SubnetIds:
      - !Ref Subnet
    SecurityGroupIds:
      - !Ref VPCEndpointSecurityGroup
    PrivateDnsEnabled: true
SSMMessagesVPCEndpoint:
  Type: AWS::EC2::VPCEndpoint
  Properties:
    VpcId: !Ref VPC
    ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssmmessages'
    VpcEndpointType: Interface
    SubnetIds:
      - !Ref Subnet
    SecurityGroupIds:
      - !Ref VPCEndpointSecurityGroup
    PrivateDnsEnabled: true
```
**特徴**:
- Interface型(ENIベース)
- プライベートサブネット内にネットワークインターフェースを作成
- プライベートDNSを有効化してサービスエンドポイントを解決
- 専用のセキュリティグループで保護
- インターネットゲートウェイなしでSSM Session Managerを使用可能
## データモデル
### パラメータデータ構造
```yaml
Parameters:
  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
    Description: 'EC2インスタンスタイプ'
  RandomSuffix:
    Type: String
    Default: '12345678'
    AllowedPattern: '^\d{8}$'
    MinLength: 8
    MaxLength: 8
    Description: 'リソース名の一意性を保証するランダムな8桁の数値'
```
### リソース命名規則
リソースは以下の形式でNameタグを持つ:
**S3以外のリソース**:
```
Dev-{AWSサービス}-{用途}-{連番}
```
**S3バケットのみ**:
```
Dev-{AWSサービス}-{用途}-{連番}-{ランダム8桁}
```
例:
- EC2インスタンス: `Dev-EC2-Linux-01`
- セキュリティグループ: `Dev-SG-Web-01`
- IAMロール: `Dev-IAM-EC2Role-01`
- インスタンスプロファイル: `Dev-IAM-InstanceProfile-01`
- VPC: `Dev-VPC-Main-01`
- Subnet: `Dev-Subnet-Private-01`
- Route Table: `Dev-RouteTable-Private-01`
- S3バケット: `Dev-S3-Data-01-87654321` (ランダム8桁付き)
連番は2桁のゼロパディング形式(01、02、03...)を使用します。
S3バケットのみ、ランダム8桁を追加して一意性を保証します。
### S3バケット命名規則
S3バケット名は、Nameタグと同じ形式を使用します:
```
dev-s3-data-01-{ランダム8桁}
```
注意点:
- S3バケット名は小文字のみ使用可能
- ハイフンで区切る
- グローバルに一意である必要がある
- ランダム8桁により一意性を保証
例: `dev-s3-data-01-87654321`
## 正確性プロパティ
プロパティとは、システムのすべての有効な実行において真であるべき特性や動作のことです。プロパティは、人間が読める仕様と機械で検証可能な正確性保証の橋渡しとなります。
### テンプレート構造プロパティ
**プロパティ1: EC2インスタンスリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、EC2インスタンスリソースが存在し、InstanceTypeプロパティがパラメータ参照を含む場合、そのテンプレートは設定可能なインスタンスタイプを持つ
**検証: 要件 1.1**
**プロパティ2: S3バケットリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、S3バケットリソースが存在し、BucketNameプロパティが命名規則に従う場合、そのテンプレートは適切な命名規則を持つ
**検証: 要件 1.2, 3.1**
**プロパティ3: IAMロールリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、IAMロールリソースが存在し、S3アクセス権限(ListBucket、GetObject、PutObject)を含むポリシーを持つ場合、そのテンプレートはS3アクセス権限を持つIAMロールを定義する
**検証: 要件 1.3, 4.1, 4.2, 4.3**
**プロパティ4: インスタンスプロファイルリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、インスタンスプロファイルリソースが存在し、IAMロールを参照している場合、そのテンプレートはIAMロールをEC2インスタンスに関連付けるインスタンスプロファイルを定義する
**検証: 要件 1.4**
**プロパティ5: セキュリティグループリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、セキュリティグループリソースが存在する場合、そのテンプレートはEC2インスタンス用のセキュリティグループを定義する
**検証: 要件 1.5**
**プロパティ6: パラメータの定義**
すべての有効なCloudFormationテンプレートにおいて、Parametersセクションに「InstanceType」と「BucketNamePrefix」が含まれる場合、そのテンプレートはカスタマイズ可能な値のためのパラメータを含む
**検証: 要件 1.10**
**プロパティ7: 出力の定義**
すべての有効なCloudFormationテンプレートにおいて、Outputsセクションに「InstanceId」、「BucketName」、「IAMRoleArn」が含まれる場合、そのテンプレートは作成されたリソース識別子のための出力を含む
**検証: 要件 1.11, 7.1, 7.2, 7.3**
**プロパティ8: Nameタグの命名規則**
すべての有効なCloudFormationテンプレートにおいて、S3以外のすべてのリソースがNameタグを持ち、その値が「Dev-{AWSサービス}-{用途}-{連番}」の形式に従い、S3バケットのみが「Dev-{AWSサービス}-{用途}-{連番}-{ランダム8桁}」の形式に従う場合、そのテンプレートは統一された命名規則を持つ
**検証: 要件 1.12, 1.13**
### EC2インスタンス設定プロパティ
**プロパティ9: インスタンスプロファイルのアタッチ**
すべての有効なCloudFormationテンプレートにおいて、EC2インスタンスリソースがIamInstanceProfileプロパティを持ち、インスタンスプロファイルを参照している場合、そのインスタンスはS3アクセスを有効にするためのインスタンスプロファイルをアタッチする
**検証: 要件 2.2**
**プロパティ10: セキュリティグループの関連付け**
すべての有効なCloudFormationテンプレートにおいて、EC2インスタンスリソースがSecurityGroupIdsプロパティを持ち、セキュリティグループを参照している場合、そのインスタンスはセキュリティグループを関連付ける
**検証: 要件 2.3**
**プロパティ11: Amazon Linux 2023 AMIの使用**
すべての有効なCloudFormationテンプレートにおいて、EC2インスタンスのImageIdプロパティが「al2023-ami-kernel-default」を含むSSMパラメータを参照している場合、そのインスタンスは最新のAmazon Linux 2023 AMIを使用する
**検証: 要件 2.4**
**プロパティ12: Systems Managerアクセスの有効化**
すべての有効なCloudFormationテンプレートにおいて、IAMロールが「AmazonSSMManagedInstanceCore」マネージドポリシーをアタッチしている場合、EC2インスタンスはAWS Systems Manager Session Managerを使用してアクセス可能である
**検証: 要件 2.5, 4.4, 4.5**
**プロパティ13: パブリックIPアドレスの無効化**
すべての有効なCloudFormationテンプレートにおいて、EC2インスタンスがプライベートサブネットに配置され、SubnetのMapPublicIpOnLaunchがfalseに設定されている場合、そのインスタンスはパブリックIPアドレスを持たない
**検証: 要件 2.6**
### S3バケット設定プロパティ
**プロパティ14: バージョニングの有効化**
すべての有効なCloudFormationテンプレートにおいて、S3バケットのVersioningConfigurationのStatusが「Enabled」に設定されている場合、そのバケットはデータ保護のためにバージョニングを有効にする
**検証: 要件 3.2**
**プロパティ15: サーバー側暗号化の有効化**
すべての有効なCloudFormationテンプレートにおいて、S3バケットのBucketEncryptionが設定され、SSEAlgorithmが指定されている場合、そのバケットはデフォルトでサーバー側暗号化を有効にする
**検証: 要件 3.3**
**プロパティ16: パブリックアクセスのブロック**
すべての有効なCloudFormationテンプレートにおいて、S3バケットのPublicAccessBlockConfigurationのすべてのプロパティ(BlockPublicAcls、BlockPublicPolicy、IgnorePublicAcls、RestrictPublicBuckets)がtrueに設定されている場合、そのバケットはデフォルトでパブリックアクセスをブロックする
**検証: 要件 3.4**
**プロパティ17: バケットの保持ポリシー**
すべての有効なCloudFormationテンプレートにおいて、S3バケットのDeletionPolicyが「Retain」に設定されている場合、スタック削除時にそのバケットはデータ損失を防ぐために保持される
**検証: 要件 3.5**
### IAMロールと権限プロパティ
**プロパティ18: 最小権限の原則(S3アクセス)**
すべての有効なCloudFormationテンプレートにおいて、IAMロールのS3ポリシーのResourceプロパティが特定のバケットARNのみを参照している場合、そのロールは最小権限の原則に従う
**検証: 要件 4.6**
**プロパティ19: EC2信頼ポリシー**
すべての有効なCloudFormationテンプレートにおいて、IAMロールのAssumeRolePolicyDocumentのPrincipalに「ec2.amazonaws.com」が含まれる場合、そのロールはEC2サービスがロールを引き受けることを許可する
**検証: 要件 4.7**
### セキュリティグループプロパティ
**プロパティ20: インバウンドルールの不在**
すべての有効なCloudFormationテンプレートにおいて、セキュリティグループのSecurityGroupIngressが定義されていないか空である場合、そのセキュリティグループはAWS Systems Manager Session Managerを使用するためインバウンド通信の許可を必要としない
**検証: 要件 5.1**
**プロパティ21: アウトバウンドトラフィックの許可**
すべての有効なCloudFormationテンプレートにおいて、セキュリティグループのSecurityGroupEgressにIpProtocol「-1」とCidrIp「0.0.0.0/0」を含むルールが存在する場合、そのセキュリティグループはすべてのアウトバウンドトラフィックを許可する
**検証: 要件 5.2**
**プロパティ22: セキュリティグループルールの説明**
すべての有効なCloudFormationテンプレートにおいて、すべてのセキュリティグループルール(IngressとEgress)がDescriptionプロパティを持つ場合、そのセキュリティグループは各ルールの説明を含む
**検証: 要件 5.3**
### テンプレート検証プロパティ
**プロパティ23: CloudFormation検証のラウンドトリップ**
すべてのCloudFormationテンプレートファイルにおいて、AWS CLIの「validate-template」コマンドを実行したとき、エラーなしで成功を返す場合、そのテンプレートはCloudFormationスキーマに従って有効であり、すべての必須プロパティを含み、組み込み関数を正しく使用している
**検証: 要件 6.5, 8.1, 8.2, 8.3, 8.5**
**プロパティ24: リソース間依存関係の定義**
すべての有効なCloudFormationテンプレートにおいて、EC2インスタンスがインスタンスプロファイルとセキュリティグループを参照し、インスタンスプロファイルがIAMロールを参照している場合、そのテンプレートは必要なリソース間の依存関係を定義する
**検証: 要件 8.4**
### VPCとネットワークプロパティ
**プロパティ25: VPCリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、VPCリソースが存在し、CidrBlock、EnableDnsSupport、EnableDnsHostnamesプロパティを持つ場合、そのテンプレートは適切に設定されたVPCを定義する
**検証: 要件 1.6, 9.1, 9.2, 9.3**
**プロパティ26: Subnetリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、SubnetリソースがVPCを参照し、MapPublicIpOnLaunchがfalseに設定されている場合、そのテンプレートはプライベートサブネットを定義する
**検証: 要件 1.7, 9.4, 9.5**
**プロパティ27: EC2インスタンスのSubnet配置**
すべての有効なCloudFormationテンプレートにおいて、EC2インスタンスがSubnetIdプロパティでSubnetを参照している場合、そのインスタンスは指定されたSubnet内に配置される
**検証: 要件 9.6**
**プロパティ28: VPCエンドポイントリソースの定義**
すべての有効なCloudFormationテンプレートにおいて、VPCエンドポイントリソースが存在し、ServiceNameが「com.amazonaws.{Region}.s3」を含み、VpcEndpointTypeが「Gateway」である場合、そのテンプレートはS3用のGateway型VPCエンドポイントを定義する
**検証: 要件 1.8, 10.1, 10.2**
**プロパティ29: VPCエンドポイントのVPC関連付け**
すべての有効なCloudFormationテンプレートにおいて、VPCエンドポイントがVpcIdプロパティでVPCを参照している場合、そのVPCエンドポイントは指定されたVPCに関連付けられる
**検証: 要件 10.3**
**プロパティ30: VPCエンドポイントのルートテーブル関連付け**
すべての有効なCloudFormationテンプレートにおいて、VPCエンドポイントがRouteTableIdsプロパティでルートテーブルを参照している場合、そのVPCエンドポイントはルートテーブルに自動的に関連付けられる
**検証: 要件 10.4**
**プロパティ31: Security GroupのVPC関連付け**
すべての有効なCloudFormationテンプレートにおいて、Security GroupがVpcIdプロパティでVPCを参照している場合、そのSecurity Groupは指定されたVPCに関連付けられる
**検証: 要件 9.6(間接的)**
## エラーハンドリング
### テンプレート検証エラー
**エラーケース**: テンプレートがCloudFormationスキーマに準拠していない
**処理**:
- AWS CLIの`validate-template`コマンドを使用して事前検証
- エラーメッセージを解析して具体的な問題を特定
- 修正後に再検証
**例**:
```bash
aws cloudformation validate-template --template-body file://template.yaml
```
### パラメータ検証エラー
**エラーケース**: 無効なパラメータ値が提供された
**処理**:
- AllowedValuesとAllowedPatternによる制約
- MinLength/MaxLengthによる長さ制限
- CloudFormationが自動的に検証し、エラーを返す
**例**:
```yaml
Parameters:
  BucketNamePrefix:
    Type: String
    AllowedPattern: '^[a-z0-9][a-z0-9-]*[a-z0-9]$'
    ConstraintDescription: 'バケット名は小文字英数字とハイフンのみを含む必要があります'
```
### リソース作成エラー
**エラーケース**: リソース作成中にエラーが発生
**処理**:
- CloudFormationの自動ロールバック機能
- スタックイベントログでエラー原因を確認
- 必要に応じてテンプレートを修正して再デプロイ
**例**:
- S3バケット名の重複
- IAM権限の不足
- リソース制限の超過
### 依存関係エラー
**エラーケース**: リソース間の依存関係が正しく解決されない
**処理**:
- CloudFormationが自動的に依存関係を解決
- 明示的な`DependsOn`属性が必要な場合は追加
- リソース参照(Ref、GetAtt)により暗黙的な依存関係を確立
**例**:
```yaml
EC2Instance:
  Type: AWS::EC2::Instance
  Properties:
    IamInstanceProfile: !Ref InstanceProfile  # 暗黙的な依存関係
```
### スタック削除エラー
**エラーケース**: S3バケットが空でないためスタック削除が失敗
**処理**:
- DeletionPolicy: Retainにより、スタック削除時にバケットを保持
- 手動でバケットを空にしてから削除
- または、バケットを保持したままスタックのみ削除
## テスト戦略
### テストアプローチ
本プロジェクトでは、AWS CLIを使用したテンプレート検証を中心としたテストアプローチを採用します。CloudFormationテンプレートは宣言的な設定ファイルであり、複雑なロジックを含まないため、構文検証と実際のデプロイテストで十分な品質を確保できます。
### AWS CLIによる検証(推奨)
#### 1. テンプレート構文検証
**目的**: テンプレートがCloudFormationスキーマに準拠することを確認
**コマンド**:
```bash
aws cloudformation validate-template --template-body file://template.yaml
```
**確認項目**:
- YAML構文の正確性
- CloudFormationリソースタイプの有効性
- 必須プロパティの存在
- 組み込み関数の正しい使用
**期待される出力**:
```json
{
    "Parameters": [...],
    "Description": "EC2とS3の通信環境を構築するテンプレート"
}
```
エラーがある場合は、詳細なエラーメッセージが表示されます。
#### 2. 変更セットによる事前検証
**目的**: 実際にリソースを作成せずに、テンプレートの変更内容を確認
**コマンド**:
```bash
# 変更セットの作成
aws cloudformation create-change-set \
  --stack-name ec2-s3-test-stack \
  --template-body file://template.yaml \
  --parameters ParameterKey=InstanceType,ParameterValue=t3.micro \
               ParameterKey=RandomSuffix,ParameterValue=12345678 \
  --change-set-name test-changeset \
  --capabilities CAPABILITY_IAM
# 変更セットの確認
aws cloudformation describe-change-set \
  --stack-name ec2-s3-test-stack \
  --change-set-name test-changeset
```
**確認項目**:
- 作成されるリソースのリスト
- リソース間の依存関係
- IAM権限の要件
- 潜在的な問題の警告
#### 3. テスト環境でのスタック作成
**目的**: 実際のAWS環境でテンプレートが正しく動作することを確認
**コマンド**:
```bash
# スタックの作成
aws cloudformation create-stack \
  --stack-name ec2-s3-test-stack \
  --template-body file://template.yaml \
  --parameters ParameterKey=InstanceType,ParameterValue=t3.micro \
               ParameterKey=RandomSuffix,ParameterValue=12345678 \
  --capabilities CAPABILITY_IAM
# スタック作成の進行状況を確認
aws cloudformation describe-stack-events \
  --stack-name ec2-s3-test-stack
# スタックの状態を確認
aws cloudformation describe-stacks \
  --stack-name ec2-s3-test-stack
```
**確認項目**:
- すべてのリソースが正常に作成される
- スタックステータスが`CREATE_COMPLETE`になる
- エラーが発生した場合は自動的にロールバックされる
#### 4. 機能テスト
**目的**: 作成されたリソースが期待通りに動作することを確認
**テスト手順**:
a. **EC2インスタンスへの接続テスト**:
```bash
# Session Manager経由で接続
aws ssm start-session --target 
```
b. **S3バケットへのアクセステスト**:
```bash
# EC2インスタンス内で実行
aws s3 ls s3://
echo "test" > test.txt
aws s3 cp test.txt s3:///
aws s3 ls s3:///
```
c. **VPCエンドポイント経由の通信確認**:
```bash
# EC2インスタンス内で実行
# VPCエンドポイント経由でS3にアクセスしていることを確認
aws s3 ls --debug 2>&1 | grep -i endpoint
```
#### 5. クリーンアップ
**目的**: テストリソースを削除してコストを削減
**コマンド**:
```bash
# S3バケットを空にする(DeletionPolicy: Retainの場合)
aws s3 rm s3:// --recursive
# スタックの削除
aws cloudformation delete-stack --stack-name ec2-s3-test-stack
# 削除の完了を確認
aws cloudformation wait stack-delete-complete --stack-name ec2-s3-test-stack
```
### テストチェックリスト
デプロイ前に以下の項目を確認:
- [ ] `validate-template`コマンドがエラーなしで成功する
- [ ] 変更セットで作成されるリソースが期待通りである
- [ ] テスト環境でスタックが正常に作成される
- [ ] EC2インスタンスにSession Manager経由で接続できる
- [ ] EC2インスタンスからS3バケットにアクセスできる
- [ ] VPCエンドポイント経由でS3通信が行われている
- [ ] すべてのリソースに正しいNameタグが付与されている
- [ ] セキュリティグループのルールが期待通りである
- [ ] IAMロールの権限が最小権限の原則に従っている
### 継続的な検証
**推奨プラクティス**:
1. **バージョン管理**: テンプレートをGitなどのバージョン管理システムで管理
2. **変更前の検証**: テンプレートを変更するたびに`validate-template`を実行
3. **段階的なデプロイ**: テスト環境 → ステージング環境 → 本番環境の順にデプロイ
4. **ドキュメント化**: 変更内容と理由をコミットメッセージに記録
### トラブルシューティング
**よくあるエラーと対処法**:
1. **構文エラー**:
   - YAMLのインデントを確認
   - 引用符の使用を確認
   - オンラインYAMLバリデーターで検証
2. **リソース作成エラー**:
   - CloudFormationイベントログで詳細を確認
   - IAM権限が不足していないか確認
   - リソース制限に達していないか確認
3. **依存関係エラー**:
   - リソース間の参照(Ref、GetAtt)を確認
   - 必要に応じてDependsOn属性を追加
4. **ロールバックエラー**:
   - S3バケットが空であることを確認
   - 手動で作成したリソースとの競合を確認

続いて、Kiro に「タスク作成フェーズ」に進むと伝えます。

実装タスクの作成

「タスク作成フェーズ」に進むと、実装のためのタスクリストである「tasks.md」を作成してくれました。

最初に作成された「tasks.md」は以下の内容です。

tasks.md

# タスクリスト
## 1. CloudFormationテンプレートの作成
- [ ] 1.1 基本構造とパラメータの定義
  - テンプレートファイル `AssociatedFolder/template.yaml` を作成
  - AWSTemplateFormatVersion、Description を定義
  - Parameters セクションを作成(InstanceType、RandomSuffix)
  - Outputs セクションの骨組みを作成
- [ ] 1.2 ネットワークリソースの定義
  - VPC リソースを定義(CIDR: 10.0.0.0/16、DNS有効化)
  - Subnet リソースを定義(CIDR: 10.0.1.0/24、プライベート設定)
  - Route Table リソースを定義
  - Subnet と Route Table の関連付けを定義
  - 各リソースに適切な Name タグを付与(ランダム8桁なし)
- [ ] 1.3 VPCエンドポイントの定義
  - S3用 VPC Endpoint リソースを定義(Gateway タイプ)
  - VPC と Route Table への参照を設定
- [ ] 1.4 IAMロールとインスタンスプロファイルの定義
  - IAM Role リソースを定義
  - EC2 信頼ポリシーを設定
  - S3 アクセスポリシーを定義(ListBucket、GetObject、PutObject)
  - Systems Manager マネージドポリシーをアタッチ
  - Instance Profile リソースを定義
  - 適切な Name タグを付与(ランダム8桁なし)
- [ ] 1.5 セキュリティグループの定義
  - Security Group リソースを定義
  - VPC への参照を設定
  - アウトバウンドルールを定義(全トラフィック許可)
  - ルールに説明を追加
  - 適切な Name タグを付与(ランダム8桁なし)
- [ ] 1.6 EC2インスタンスの定義
  - EC2 Instance リソースを定義
  - 最新の Amazon Linux 2023 AMI を SSM パラメータストアから取得
  - Instance Profile、Subnet、Security Group への参照を設定
  - 適切な Name タグを付与(ランダム8桁なし)
- [ ] 1.7 S3バケットの定義
  - S3 Bucket リソースを定義
  - バケット名を設定(小文字、ランダム8桁サフィックス付き)
  - バージョニングを有効化
  - サーバー側暗号化を設定(AES256)
  - パブリックアクセスブロックを設定
  - DeletionPolicy と UpdateReplacePolicy を Retain に設定
  - 適切な Name タグを付与(ランダム8桁付き)
- [ ] 1.8 出力の定義
  - EC2 Instance ID の出力を定義
  - S3 Bucket Name の出力を定義
  - IAM Role ARN の出力を定義
  - Export 名を設定
## 2. テンプレートの検証
- [ ] 2.1 AWS CLI環境の確認
  - AWS CLI がインストールされているか確認
  - AWS 認証情報が設定されているか確認(`aws sts get-caller-identity` で確認)
- [ ] 2.2 テンプレート構文の検証
  - `aws cloudformation validate-template` コマンドでテンプレートを検証
  - エラーがあれば修正
## 3. CloudFormationスタックのデプロイ
- [ ] 3.1 デプロイ用スクリプトの作成
  - デプロイ用の PowerShell スクリプト `AssociatedFolder/deploy.ps1` を作成
  - スタック名、パラメータ値を設定
  - create-stack コマンドを含める
  - エラーハンドリングを追加
- [ ] 3.2 スタックの作成
  - deploy.ps1 スクリプトを実行してスタックを作成
  - スタック作成の進行状況を確認
  - CREATE_COMPLETE ステータスになるまで待機
- [ ] 3.3 作成されたリソースの確認
  - スタックの出力値を確認(Instance ID、Bucket Name、Role ARN)
  - AWS コンソールまたは CLI でリソースが正しく作成されたか確認
  - Name タグが正しく付与されているか確認
## 4. 機能テスト
- [ ] 4.1 EC2インスタンスへの接続テスト
  - Systems Manager Session Manager 経由で EC2 インスタンスに接続
  - 接続が成功することを確認
- [ ] 4.2 S3バケットへのアクセステスト
  - EC2 インスタンス内から S3 バケットへのアクセスをテスト
  - `aws s3 ls` コマンドでバケット一覧を取得
  - テストファイルをアップロード
  - テストファイルをダウンロード
  - IAM ロールの権限が正しく機能していることを確認
- [ ] 4.3 VPCエンドポイント経由の通信確認
  - EC2 インスタンス内から S3 へのアクセスが VPC エンドポイント経由であることを確認
  - `aws s3 ls --debug` コマンドで接続先エンドポイントを確認
## 5. ドキュメント作成
- [ ] 5.1 デプロイ手順書の作成
  - `AssociatedFolder/README.md` を作成
  - 前提条件を記載
  - デプロイ手順を記載
  - テスト手順を記載
  - クリーンアップ手順を記載
- [ ] 5.2 クリーンアップスクリプトの作成
  - クリーンアップ用の PowerShell スクリプト `AssociatedFolder/cleanup.ps1` を作成
  - S3 バケットを空にするコマンドを含める
  - スタック削除コマンドを含める
  - 削除完了の確認を含める
## 6. 最終確認とクリーンアップ(オプション)
- [ ]* 6.1 スタックの更新テスト
  - テンプレートに小さな変更を加える
  - update-stack コマンドでスタックを更新
  - 変更が正しく適用されることを確認
- [ ]* 6.2 テスト環境のクリーンアップ
  - cleanup.ps1 スクリプトを実行
  - S3 バケットが空になることを確認
  - スタックが削除されることを確認
  - S3 バケットが保持されることを確認(DeletionPolicy: Retain)

実装の流れは以下のとおりです。
実装時に行うべき内容が整理されており、学びが多い構成でした。

  1. CloudFormationテンプレートの作成
  2. テンプレートの検証
  3. CloudFormationスタックのデプロイ
  4. 機能テスト
  5. ドキュメント作成
  6. 最終確認とクリーンアップ(オプション)

作成されたテンプレートファイルは以下です。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Description: 'EC2 and S3 Communication Environment CloudFormation Template'
Parameters:
  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
    Description: 'EC2 Instance Type'
  RandomSuffix:
    Type: String
    Default: '12345678'
    AllowedPattern: '^\d{8}$'
    MinLength: 8
    MaxLength: 8
    Description: 'Random 8-digit number for resource name uniqueness'
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: 'Dev-VPC-Main-01'
  Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: 'Dev-Subnet-Private-01'
  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: 'Dev-RouteTable-Private-01'
  SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Subnet
      RouteTableId: !Ref RouteTable
  S3VPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref RouteTable
  VPCEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: 'Dev-SG-VPCEndpoint-01'
      GroupDescription: 'Security group for VPC Endpoints'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !Ref SecurityGroup
          Description: 'Allow HTTPS from EC2 instances'
      Tags:
        - Key: Name
          Value: 'Dev-SG-VPCEndpoint-01'
  SSMVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssm'
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref VPCEndpointSecurityGroup
      PrivateDnsEnabled: true
  SSMMessagesVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssmmessages'
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref VPCEndpointSecurityGroup
      PrivateDnsEnabled: true
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 'Dev-IAM-EC2Role-01'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
      Policies:
        - PolicyName: S3AccessPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - 's3:ListBucket'
                Resource: !GetAtt S3Bucket.Arn
              - Effect: Allow
                Action:
                  - 's3:GetObject'
                  - 's3:PutObject'
                Resource: !Sub '${S3Bucket.Arn}/*'
      Tags:
        - Key: Name
          Value: 'Dev-IAM-EC2Role-01'
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: 'Dev-IAM-InstanceProfile-01'
      Roles:
        - !Ref EC2Role
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: 'Dev-SG-Web-01'
      GroupDescription: 'Security group for EC2 instance with S3 access'
      VpcId: !Ref VPC
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
          Description: 'Allow all outbound traffic for S3 and Systems Manager access'
      Tags:
        - Key: Name
          Value: 'Dev-SG-Web-01'
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}'
      InstanceType: !Ref InstanceType
      IamInstanceProfile: !Ref InstanceProfile
      SubnetId: !Ref Subnet
      SecurityGroupIds:
        - !Ref SecurityGroup
      Tags:
        - Key: Name
          Value: 'Dev-EC2-Linux-01'
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'dev-s3-data-01-${RandomSuffix}'
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: Name
          Value: !Sub 'Dev-S3-Data-01-${RandomSuffix}'
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
Outputs:
  InstanceId:
    Description: 'EC2 Instance ID'
    Value: !Ref EC2Instance
    Export:
      Name: !Sub '${AWS::StackName}-InstanceId'
  BucketName:
    Description: 'S3 Bucket Name'
    Value: !Ref S3Bucket
    Export:
      Name: !Sub '${AWS::StackName}-BucketName'
  IAMRoleArn:
    Description: 'IAM Role ARN'
    Value: !GetAtt EC2Role.Arn
    Export:
      Name: !Sub '${AWS::StackName}-IAMRoleArn'
  VPCId:
    Description: 'VPC ID'
    Value: !Ref VPC
    Export:
      Name: !Sub '${AWS::StackName}-VPCId'
  SubnetId:
    Description: 'Subnet ID'
    Value: !Ref Subnet
    Export:
      Name: !Sub '${AWS::StackName}-SubnetId'

実装内容の定義が完了したため、タスクの実行による実装を Kiro に伝えます。

タスクリストに従った実装

Kiro がタスクリストに従って順次実装を進めます。

タスクが完了すると、以下のように[ ]にチェックを入力して進捗を表示します。
(タスクリストの内容は、先ほど記載した内容から修正を経由しています)

tasks.md

# タスクリスト
## 1. CloudFormationテンプレートの作成
- [x] 1.1 基本構造とパラメータの定義
  - テンプレートファイル `AssociatedFolder/template.yaml` を作成
  - AWSTemplateFormatVersion、Description を定義
  - Parameters セクションを作成(InstanceType、RandomSuffix)
  - Outputs セクションの骨組みを作成
- [x] 1.2 ネットワークリソースの定義
  - VPC リソースを定義(CIDR: 10.0.0.0/16、DNS有効化)
  - Subnet リソースを定義(CIDR: 10.0.1.0/24、プライベート設定)
  - Route Table リソースを定義
  - Subnet と Route Table の関連付けを定義
  - 各リソースに適切な Name タグを付与(ランダム8桁なし)
- [-] 1.3 VPCエンドポイントの定義
  - S3用 VPC Endpoint リソースを定義(Gateway タイプ)
  - VPC と Route Table への参照を設定
  - SSM用 VPC Endpoint Security Group リソースを定義
  - SSM用 VPC Endpoints リソースを定義(Interface タイプ)
    - com.amazonaws.region.ssm
    - com.amazonaws.region.ssmmessages
  - VPC、Subnet、Security Group への参照を設定
  - PrivateDnsEnabled を true に設定
  - ※注: テンプレートには追加済み、スタック更新が必要
- [x] 1.4 IAMロールとインスタンスプロファイルの定義
  - IAM Role リソースを定義
  - EC2 信頼ポリシーを設定
  - S3 アクセスポリシーを定義(ListBucket、GetObject、PutObject)
  - Systems Manager マネージドポリシーをアタッチ
  - Instance Profile リソースを定義
  - 適切な Name タグを付与(ランダム8桁なし)
- [x] 1.5 セキュリティグループの定義
  - Security Group リソースを定義
  - VPC への参照を設定
  - アウトバウンドルールを定義(全トラフィック許可)
  - ルールに説明を追加
  - 適切な Name タグを付与(ランダム8桁なし)
- [x] 1.6 EC2インスタンスの定義
  - EC2 Instance リソースを定義
  - 最新の Amazon Linux 2023 AMI を SSM パラメータストアから取得
  - Instance Profile、Subnet、Security Group への参照を設定
  - 適切な Name タグを付与(ランダム8桁なし)
- [x] 1.7 S3バケットの定義
  - S3 Bucket リソースを定義
  - バケット名を設定(小文字、ランダム8桁サフィックス付き)
  - バージョニングを有効化
  - サーバー側暗号化を設定(AES256)
  - パブリックアクセスブロックを設定
  - DeletionPolicy と UpdateReplacePolicy を Retain に設定
  - 適切な Name タグを付与(ランダム8桁付き)
- [x] 1.8 出力の定義
  - EC2 Instance ID の出力を定義
  - S3 Bucket Name の出力を定義
  - IAM Role ARN の出力を定義
  - Export 名を設定
## 2. テンプレートの検証
- [x] 2.1 AWS CLI環境の確認
  - AWS CLI がインストールされているか確認
  - AWS 認証情報が設定されているか確認(`aws sts get-caller-identity` で確認)
- [ ] 2.2 テンプレート構文の検証
  - `aws cloudformation validate-template` コマンドでテンプレートを検証
  - エラーがあれば修正
## 3. CloudFormationスタックのデプロイ
- [ ] 3.1 デプロイ用スクリプトの作成
  - デプロイ用の PowerShell スクリプト `AssociatedFolder/deploy.ps1` を作成
  - スタック名、パラメータ値を設定
  - create-stack コマンドを含める
  - エラーハンドリングを追加
  - ※注: このタスクはスキップされました(Kiro経由で直接デプロイ)
- [-] 3.2 スタックの作成
  - AWS CLI経由でスタックを作成
  - スタック作成の進行状況を確認
  - CREATE_COMPLETE ステータスになるまで待機
  - ※注: 初回作成は完了、SSM VPCエンドポイント追加のため更新が必要
- [-] 3.3 作成されたリソースの確認
  - スタックの出力値を確認(Instance ID、Bucket Name、Role ARN)
  - AWS コンソールまたは CLI でリソースが正しく作成されたか確認
  - Name タグが正しく付与されているか確認
  - ※注: 初回リソースは確認済み、SSM VPCエンドポイントの確認が必要
- [ ] 3.4 スタックの更新(SSM VPCエンドポイント追加)
  - テンプレートにSSM用VPCエンドポイントを追加
  - update-stack コマンドでスタックを更新
  - 更新が正常に完了することを確認
## 4. 機能テスト
- [ ] 4.1 EC2インスタンスへの接続テスト
  - Systems Manager Session Manager 経由で EC2 インスタンスに接続
  - 接続が成功することを確認
- [ ] 4.2 S3バケットへのアクセステスト
  - EC2 インスタンス内から S3 バケットへのアクセスをテスト
  - `aws s3 ls` コマンドでバケット一覧を取得
  - テストファイルをアップロード
  - テストファイルをダウンロード
  - IAM ロールの権限が正しく機能していることを確認
- [ ] 4.3 VPCエンドポイント経由の通信確認
  - EC2 インスタンス内から S3 へのアクセスが VPC エンドポイント経由であることを確認
  - `aws s3 ls --debug` コマンドで接続先エンドポイントを確認
## 5. ドキュメント作成
- [ ] 5.1 デプロイ手順書の作成
  - `AssociatedFolder/README.md` を作成
  - 前提条件を記載
  - デプロイ手順を記載
  - テスト手順を記載
  - クリーンアップ手順を記載
- [ ] 5.2 クリーンアップスクリプトの作成
  - クリーンアップ用の PowerShell スクリプト `AssociatedFolder/cleanup.ps1` を作成
  - S3 バケットを空にするコマンドを含める
  - スタック削除コマンドを含める
  - 削除完了の確認を含める
## 6. 最終確認とクリーンアップ(オプション)
- [ ]* 6.1 スタックの更新テスト
  - テンプレートに小さな変更を加える
  - update-stack コマンドでスタックを更新
  - 変更が正しく適用されることを確認
- [ ]* 6.2 テスト環境のクリーンアップ
  - cleanup.ps1 スクリプトを実行
  - S3 バケットが空になることを確認
  - スタックが削除されることを確認
  - S3 バケットが保持されることを確認(DeletionPolicy: Retain)

タスクの実行に合わせて、AWS リソースの作成やテストの実施状況を確認できました。
最終的に AWS リソースの削除まで行い、全フェーズが完了しました。

タスク失敗の挙動確認

挙動確認のため、Kiro 実行端末から AWS 認証情報を削除し、タスク 2.1 を意図的に失敗させました。

- [ ] 2.1 AWS CLI環境の確認
  - AWS CLI がインストールされているか確認
  - AWS 認証情報が設定されているか確認(`aws sts get-caller-identity` で確認)

Kiro は「aws sts get-caller-identity」に対するエラーから、AWS 認証情報がないことを認識しました。
エラーの解決方法として、AWS 認証情報の設定を提案してきます。

設定のサポートをお願いすると、分かりやすい手順が提供され、驚きました。

Kiro を触る中で感じた課題

Spec ファイルが煩雑になってしまった

開発を進める中で、様々な変更を Kiro に伝えました。
Kiro は伝えた変更が関係する Spec ファイルを横断的に修正できます。

しかし変更が多いためか、以下の問題が生じました。

  • ドキュメントが冗長になる
  • 本来は複数のファイルや記述を修正すべきところを、単一の文章のみ修正して完了とみなすことがあった
  • タスク失敗に伴い対応方法を変更しても、ドキュメントが更新されないことがあった

細かい IAM ポリシーの定義に失敗した

タスク失敗の挙動確認」では、タスクリストの実行に必要な IAM ポリシーを提示してもらいました。
ここで許可を限定するため、リソースの更新と削除を Name タグで制御するように依頼したところ、以下の問題が発生しました。

  • ポリシーに使用できないアクションが 2 つ含まれている
  • 依頼していない「リソース作成」にもタグでの制御が記載された

バイアスにより、伝えた内容を失念することがある

デプロイ先のリージョンを誤る

大阪リージョン(ap-northeast-3)での作成を指示していたにもかかわらず、コマンドで東京リージョン(ap-northeast-1)を明示し、リソースがそちらに作成されていました。

過去の仕様に戻ってしまう

当初、Kiroが作成した「design.md」とテンプレートファイルには、Systems Manager 用の VPC エンドポイントが 3 つ記載されていました。

  • com.amazonaws.region.ssm
  • com.amazonaws.region.ec2messages
  • com.amazonaws.region.ssmmessages

SSM Agent バージョン 3.3.40.0 以降は「com.amazonaws.region.ec2messages」が不要³なため、修正を Kiro に依頼したところ、バイアスが以下やり取りで現れました。

  1. 筆者:現在は 2 つで問題ないためテンプレートファイルを修正するよう依頼
  2. Kiro:最新情報より 2 つで問題ことを確認、テンプレートファイルから「com.amazonaws.region.ec2messages」を削除
  3. 筆者:「design.md」の記載も 2 つに修正することを依頼
  4. Kiro:「com.amazonaws.region.ec2messages」は必要な VPC エンドポイントのため、テンプレートファイルに再度記載
  5. 筆者:「com.amazonaws.region.ssm」と「com.amazonaws.region.ssmmessages」のみで問題ないと明示
  6. Kiro:「design.md」とテンプレートファイルから「com.amazonaws.region.ec2messages」を削除

Kiro を使用する際のコツ

今回 Kiro を使用してみて、以下を意識して開発することが重要だと学びました。

要件を不足なく Kiro に明示すること

⇒後から追加指示をすると、修正が重なり時間を要し、ドキュメントも冗長になります。

要件に基づいて Spec ファイルをレビューし、不足や改善点を洗い出すこと

⇒ Kiro が Spec ファイルに記載した設計だけに依存せず、要件を実現する更に優れた方法がないか、自身で気づく必要があります。

Kiro が提案するコマンド(特に実装時)は、確認してから実行すること

⇒事前に Kiro に伝えた指示から乖離していることがあります。

レビューの精度を上げるため、Spec ファイルを自身が理解しやすい形式に整理すること

⇒たとえば当初は Python を用いたテストを計画していましたが、AWS CLI コマンドによるテストに変更しました。

終わりに

本記事では、Kiro を初めて触る筆者が CloudFormation テンプレートファイルを作成した体験談を記載しました。
試行錯誤の結果、作業時間は約 5 時間、Credits は 78.75 使っていました。

全体を通して感じたことは、Kiro での開発は、エンジニアのスキルアップにも非常に有用であることです
実装の流れを段階的に体験でき、各ステップで必要なポイントを把握できます。
興味のある技術や内容の成果物を作成できるため、理解とインプットがスムーズに進みます。

今回の体験を機に、社外で操作デモの機会もいただき、良い経験になりました。

本記事が少しでもお役に立てば幸いです。

参考文献

¹ "Installation - IDE - Docs - Kiro". kiro.dev. https://kiro.dev/docs/getting-started/installation/, (参照 2025-01-20)
² "仕様駆動開発で作った Spec ファイルってどうするの ? ~ 仕様とコードの乖離問題を考えてみる ~ - builders.flash☆ - 変化を求めるデベロッパーを応援するウェブマガジン | AWS". AWS. https://aws.amazon.com/jp/builders-flash/202601/specification-code-deiscrepancy/, (参照 2025-01-19)
³ "Systems Manager のために VPC エンドポイントを使用して EC2 インスタンスのセキュリティを強化する - AWS Systems Manager". AWS Documentation. https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/setup-create-vpc.html, (参照 2025-01-21)

※掲載したスクリーンショットと、以下のファイルの文面は Kiro ver0.8.86 (Amazon.com, Inc.) の出力より引用しています。
requirements.md
design.md
tasks.md
template.yaml

この記事は私が書きました

Hirano

記事一覧

AWSの知見を身につけるため、一大決心でP&Sに入社しました。 目標はシステム改善に大きく貢献できるエンジニアになることです。 簡単な内容であっても自身が戸惑った点を投稿することで、同じ苦労をしている方の助けになれば嬉しいです!

Hirano

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。