1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kiro活用】Agent HooksとCodePipelineでIaC変更を安全に適用する(第3部)

1
Last updated at Posted at 2026-03-27

第1部はこちらhttps://qiita.com/REALKTMR/items/325e5c5726c0989ade1c
第2部はこちらhttps://qiita.com/REALKTMR/items/0bafb70313b6d3dff3a9


はじめに

第1部では、KiroのバイブコーディングモードでAWS三層アーキテクチャのCloudFormationテンプレートを生成し、Well-Architected Framework 30項目で採点しました(最大26/30)。

第2部では、Kiroのspecモードと詳細な仕様書を組み合わせることで、30/30満点のテンプレートを生成できることを検証しました。

第3部のテーマは「生成したIaCを、壊さずに変更し続ける仕組みを作る」 です。

Kiroでテンプレートを生成できても、その後の変更管理が甘ければ品質は劣化します。インフラは「作って終わり」ではなく、「育て続ける」ものです。

今回は以下の2つを組み合わせて、IaC変更の二段構えの安全ゲートを構築します。

  • Kiro Agent Hooks:ローカルで編集するたびに cfn-lint を自動実行し、クリーンなら commit/push まで完結
  • AWS CodePipeline:Change Set による人間レビューを経てからデプロイ

アーキテクチャ概要

パイプライン全体の流れは以下の通りです。

【ローカル:Kiro IDE】
template.yaml を編集
  ↓ 自動(fileEdited Hook 発火)
Kiro Agent Hook(cfn-lint)
  ↓ エラーあり → 修正提案。人間は「承認」するだけ
  ↓ クリーン  → 「コミットしてpushしますか?」
                  ↓ 人間が「はい。」(承認①)
               git add → git commit(メッセージ自動生成)→ git push

【クラウド:AWS】
CodePipeline 自動起動(GitHub App Webhook)
  ↓
Stage 1 Source:GitHub からソース取得
  ↓
Stage 2 Validate:CodeBuild で cfn-lint
  ↓
Stage 3 CreateChangeSet:差分プレビュー生成
  ↓
Stage 4 Approval:人間が Change Set を確認して承認(承認②)
  ↓
Stage 5 ExecuteChangeSet:スタック更新

人間がやることは2回の承認だけです。 コマンドを一切打たずに、IaC変更を安全に本番へ届けられます。

ローカルとクラウドで同じ cfn-lint を二重に実行するのは冗長に見えますが、それぞれ役割が違います。

レイヤー ツール タイミング 目的
ローカル Kiro Agent Hook 編集のたびに即座 早期フィードバック(タイプミス・構文エラー)
クラウド CodeBuild(Validate) push のたびに チーム共通のゲート
クラウド Change Set + Approval デプロイ前に 人間による破壊的変更の検知

Kiro Agent Hooks の実装

フックファイルの形式

Kiro Agent Hooks は .kiro/hooks/ ディレクトリに *.kiro.hook という形式で定義します。hooks.json のような単一ファイルではなく、フックごとに独立したファイルを置く設計です。

then.type は2種類あります。

タイプ 説明
runCommand シェルコマンドを直接実行
askAgent エージェント(LLM)にプロンプトを送信

実装したフック

今回の最終的なフック定義です。

{
  "enabled": true,
  "name": "cfn-lint on save",
  "description": "template.yaml 保存時に cfn-lint を自動実行してエラーを即座にフィードバック",
  "version": "1",
  "when": {
    "type": "fileEdited",
    "patterns": ["**/template.yaml"]
  },
  "then": {
    "type": "askAgent",
    "prompt": "pattern-3/template.yaml に対して cfn-lint を実行してください。\n\nエラー・警告がある場合:内容・行番号・修正方法を日本語で報告してください。\n\nエラー・警告がない場合:「テンプレートに問題はありません。変更をコミットしてpushしますか?」と聞いてください。ユーザーがOKと答えたら git add と git commit(変更内容から適切なメッセージを自動生成)と git push を実行してください。"
  }
}

fileEdited パターンにより、template.yaml を編集するたびにフックが発火します。エラーがあれば修正提案まで行い、クリーンであればそのまま commit/push の確認へ進む——この一連の流れを1つのフックで完結させています。

動作イメージ

エラー検出時(Kiro チャットパネルの表示)

cfn-lint で 1 件のエラーが検出されました。

・E2015(行 47):EC2InstanceType パラメータの Default 値 t4g.micr が
  AllowedValues に含まれていません。t4g.micro のタイポミスです。

修正方法:
  Default: t4g.micro  ← "t4g.micr" → "t4g.micro"

直しますか?

クリーン時(Kiro チャットパネルの表示)

テンプレートに問題はありません。変更をコミットしてpushしますか?

→「はい。」と返すと Kiro が git add → git commit → git push を自動実行します。

Steering ドキュメントでエージェントに情報を伝える

.kiro/steering/setup.md にプロジェクト固有の情報を書いておくと、エージェントは毎回それを読んでから作業します。cfn-lint のインストール状況や検証対象ファイルなどを記載しておくことで、エージェントが余計な試行をせずに動作します。

# プロジェクトセットアップ

## cfn-lint
cfn-lint はグローバルにインストール済みです。`cfn-lint` コマンドをそのまま使用してください。

.kiro/steering/ ディレクトリに置いたMarkdownファイルは、エージェントが毎回自動で読み込みます。「Including Steering Documents: setup.md」という表示がエージェントの応答に出ていれば機能しています。


CodePipeline の構築

一括構築アプローチ

パイプライン自体も CloudFormation(pattern-3/pipeline.yaml)で管理します。S3・IAMロール・SNS・CodeBuild・CodePipeline をまとめて一枚のテンプレートで定義し、aws cloudformation deploy 一発で環境が揃います。

主要リソースの構成:

リソース 用途
S3 バケット アーティファクト一時保管
IAM ロール(CodePipeline用) ソース・ステージ間の権限
IAM ロール(CodeBuild用) cfn-lint 実行権限
IAM ロール(CFnデプロイ用) Change Set 作成・実行権限
SNS トピック Approval 通知メール送信
CodeBuild プロジェクト cfn-lint 実行
CodePipeline 全ステージのオーケストレーション

buildspec.yml

CodeBuild の実行内容は pattern-3/buildspec.yml に定義しています。

version: 0.2

env:
  variables:
    TEMPLATE_PATH: "pattern-3/template.yaml"

phases:
  install:
    runtime-versions:
      python: 3.11
    commands:
      - pip install cfn-lint --quiet

  build:
    commands:
      - echo "=== cfn-lint validation ==="
      - cfn-lint ${TEMPLATE_PATH}
      - echo "cfn-lint passed"

artifacts:
  files:
    - pattern-3/template.yaml
  discard-paths: no

Triggers 設定と Stages 構成

pipeline.yaml の CodePipeline 定義の核心部分です。

Pipeline:
  Type: AWS::CodePipeline::Pipeline
  Properties:
    PipelineType: V2
    Triggers:
      - ProviderType: CodeStarSourceConnection
        GitConfiguration:
          SourceActionName: GitHub
          Push:
            - Branches:
                Includes:
                  - main
    Stages:
      - Name: Source          # GitHub からソース取得
      - Name: Validate        # CodeBuild で cfn-lint
      - Name: CreateChangeSet
        Configuration:
          ActionMode: CHANGE_SET_REPLACE
          ChangeSetName: pipeline-changeset
      - Name: Approval
        Configuration:
          NotificationArn: !Ref ApprovalTopic
      - Name: ExecuteChangeSet
        Configuration:
          ActionMode: CHANGE_SET_EXECUTE

CreateChangeSetCHANGE_SET_REPLACE)→ ApprovalExecuteChangeSetCHANGE_SET_EXECUTE)という3ステージの分離が、人間によるレビューを可能にしている構造のポイントです。


実際に動かしてわかったこと(ハマりポイント)

① CFnコンソールでパラメータ説明が文字化け(未解決)

現象template.yamlDescriptionMetadata: AWS::CloudFormation::Interface の Labels に書いた日本語が、CloudFormation コンソールで ???? と表示される

CloudFormation のテンプレートは UTF-8 で記述できるはずであり、実際にファイルのバイト列も正しい UTF-8(BOMなし・LF改行)であることを確認しました。しかし、コンソール上では日本語が ? に置換されて表示されます。

試したこと:

  • CRLF → LF への変換(file コマンドで UTF-8 LF を確認)
  • .gitattributes*.yaml text eol=lf を追加
  • CodePipeline を介さずコンソールから直接テンプレートをアップロード

いずれも改善せず。CloudFormation コンソールの GetTemplateSummary API が日本語テキストを正しく処理できていない可能性がありますが、原因は特定できていません

機能自体(スタックの作成・更新)には影響がないため、そのまま進めています。情報をお持ちの方はコメントいただけると助かります。


② 第2部で満点を取ったテンプレートも cfn-lint の警告に引っかかった

背景:第3部で使用した template.yaml は、第2部の Spec モードで生成した pattern-2b をベースにしています。第2部では Well-Architected Framework 30項目のチェックで 30/30 満点 を獲得したテンプレートです。

「完璧なテンプレートだから cfn-lint もクリアできるはず」と思っていましたが、パイプラインの Validate ステージで FAILED になりました。

現象:cfn-lint が exit status 4 を返してパイプラインが FAILED になる

cfn-lint の exit status は以下の意味を持ちます。

exit status 意味
0 問題なし
2 エラーあり(E prefix)
4 警告のみ(W prefix)
6 エラー+警告の両方

今回発生した警告:

警告コード 内容
W3011 UpdateReplacePolicyDeletionPolicy は両方設定することが推奨される
W1020 変数を使っていない Fn::Sub は不要

対処:警告を無視するオプション(--ignore-checks)を使わずに、テンプレート自体を修正しました。

Kiro が生成した高品質なテンプレートでも、cfn-lint の厳密なチェックをすべてパスするわけではありません。「WA準拠スコア」と「lintクリーン」は別軸の評価です。パイプラインにlintを組み込むことで、こういった見落としを機械的に拾えます。


③ Change Set に 41 リソースの置き換えが出た

現象:Change Set を確認すると、41 リソースが Replace: True と表示された

経緯

  1. テンプレートに EngineVersion: '8.0' と書いていたが、CloudFormation は実際に 8.0.44 で RDS をデプロイしていた
  2. cfn-lint が '8.0' を E3691(有効な値ではない)としてエラー → '8.0.44' に修正
  3. 同時に W3011 の推奨に従い、全リソースに UpdateReplacePolicy: Retain を追加
  4. 「EngineVersion の値変更」+「UpdateReplacePolicy の後付け追加」が重なり、RDS インスタンスが置き換え対象に → 依存する 40 リソースが連鎖して Replace=True に

注意:W3011 の推奨(UpdateReplacePolicyDeletionPolicy を両方設定する)自体は現在も正しいベストプラクティスです。問題は推奨に従ったことではなく、デプロイ済みのスタックに対して他の変更と同時に後付けしたことです。最初のテンプレート作成時から設定しておけば、この問題は起きませんでした。

Change Set の「リソースの変更」を開くと、RDS インスタンスが Replace: TrueReplaceAndSnapshot になっていました。

もし承認して実行していたら:

  • RDS インスタンスが削除・再作成される
  • ReplaceAndSnapshot のため削除前にスナップショットは取られる
  • しかしアプリケーションのデータベース接続は切断され、ダウンタイムが発生
  • 新しい RDS インスタンスのエンドポイントが変わるため、アプリケーションの設定変更も必要
  • 本番環境であれば、サービス停止+データ移行作業が発生していた

対処Approval ステージで「拒否」 しました。これはパイプラインが正しく機能した証拠です。破壊的な変更が本番に適用される前に人間がレビューして止められました。

Change Set があることの価値がここで実証されました。 CloudFormation をコンソールや CLI から直接 apply していたら、確認画面もなくそのまま実行されていたはずです。「ちょっとした修正のつもりが、RDS の再作成を引き起こす」——これが IaC 変更管理の怖さであり、Change Set によるレビューが欠かせない理由です。


④ CodePipeline V2 の自動トリガーが動かない

現象git push してもパイプラインが自動起動しない

原因Triggers プロパティを設定しても、CodeConnections の接続が GitHub App として認証されていないと webhook が届きません。

対処

  1. CodeConnections から既存の接続を削除
  2. 「接続を作成」から GitHub App として再インストール
  3. 新しい接続 ARN でパイプラインを更新

CodeConnections V2 の自動トリガーを使う場合は、OAuth ではなく GitHub App でインストールする ことが前提です。


⑤ Kiro Agent Hooks の仕様がドキュメントと違った

[公式ドキュメント](https://kiro.dev/docs/hooks/)では、フックの Event タイプとして「File Save」、Action タイプとして「Run Command」と記載されています。これを参考に JSON を書きましたが、Kiro 0.11 では以下のエラーが出て動作しませんでした。

Hook file has invalid data structure: Hook when.type must be one of:
fileEdited, fileCreated, fileDeleted, userTriggered, ...

実際に動作する JSON 値は以下の通りです。

項目 ドキュメント表記 JSON で動く値
when.type File Save fileEdited
then.type Run Command runCommand または askAgent
ファイルパス変数 ${file} 展開されない(ハードコードか相対パスが必要)

ドキュメントの表記(GUI 上の名称)と JSON スキーマのキー名が異なります。Kiro のバージョンアップに伴う仕様変更の可能性もあるため、実際に試して IDE のエラーメッセージで正しい値を確認するのが確実です。

また、runCommand を使うとコマンドの出力がチャットパネルに表示されません。エラー詳細を見せたい場合は askAgent を使う必要があります。

フックの実行許可ダイアログは 「Execute hook」タブ に出ます。メインの「New Session」タブには出ないため、気づかずに永遠に待ち続ける可能性があります。タスクリストの「CURRENT TASKS」を確認してください。


デモ:2つのシナリオ

シナリオ A:破壊的変更を事前検知して止める

変更内容EngineVersion を変更

Change Set の結果

項目 内容
変更リソース数 41 件
主なアクション Replace
Replace True(多数)

アクション:Approval ステージで 「拒否」 → パイプラインが FAILED で終了、スタックは変更なし


シナリオ B:安全な変更をそのまま流す

変更内容:ALB ヘルスチェック間隔を変更(1行変更)

Change Set の結果

項目 内容
変更リソース数 1 件(ALBTargetGroup)
アクション Modify
Replace False(インプレース更新)

パイプライン全ステージの結果

Source ✅ → Validate(cfn-lint) ✅ → CreateChangeSet ✅ → Approval ✅ → ExecuteChangeSet ✅

人間がやったこと:

# アクション 手段
1 template.yaml を編集 Kiro IDE
2 cfn-lint フックの「Run」を承認 クリック
3 「はい。」と返答(commit/push 確認) Kiro チャット
4 Change Set を確認して Approve AWS Console クリック

コマンドを一切打たずに、変更が本番環境に反映されました。

2つのシナリオを並べると、Change Set の価値が明確になります。

シナリオ 変更内容 Change Set 対応 結果
A EngineVersion変更 41リソース Replace=True 拒否 本番障害を未然に防止
B ヘルスチェック間隔変更 1リソース Replace=False 承認 ダウンタイムなし適用

まとめ

今回構築した二段構えの仕組みをまとめます。

レイヤー ツール 役割 タイミング
ローカル Kiro Agent Hook(cfn-lint) 最初の砦。編集のたびに即座にフィードバック&commit/push 開発中
クラウド CodeBuild(cfn-lint) チーム共通のゲート git push
クラウド Change Set + Approval 破壊的変更の人間レビュー デプロイ前

Kiro Agent Hooks は、IDE を離れずにバリデーション結果が得られます。さらに「クリーンなら commit/push まで流す」という連続したフローを1つのフックに組み込むことで、開発者がコマンドを意識しない体験を実現できます。

CodePipeline の Change Set は、「何が変わるか」を適用前に人間が確認できる仕組みです。今回のシナリオ A では、41リソースの置き換えを Approval ステージで止めました。コンソールや CLI で直接デプロイしていれば、そのまま実行されていたケースです。

Kiroで生成した高品質なテンプレートも、変更管理の仕組みがなければ時間とともに劣化します。「作って終わり」ではなく「継続的に安全に育てる」IaCを実現するには、この二段構えのゲートが有効です。


検証コード(GitHub)

.kiro/hooks/cfn-lint.kiro.hook    # Kiro Agent Hook 定義(cfn-lint + commit/push)
.kiro/steering/setup.md           # エージェント向けセットアップ情報
pattern-3/template.yaml           # 三層アーキテクチャ CFn テンプレート
pattern-3/buildspec.yml           # CodeBuild 実行仕様
pattern-3/pipeline.yaml           # パイプライン構築用 CFn テンプレート

セットアップ手順(cfn-lint のインストール):

pip install cfn-lint

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?