Kiro CLI を Lambda 関数の上で動かしてみた

Kiro CLI を Lambda 関数の上で動かしてみた

2026.04.28

はじめに

2026/04/13に Kiro CLI 2.0 がリリースされました。このバージョンに含まれる新機能として、ヘッドレスモードという動作モードが新たに実装されたことで、これまでブラウザベースでの認証が必須でしたが、API キーベースでの認証も可能となりました。

※詳しくは以下の suzuki.ryo さんの記事に記載されておりますので、合わせてご一読ください。

https://dev.classmethod.jp/articles/kiro-cli-2-0-headless-mode-api-key-auth/

そのため、例えば Lambda 関数に Kiro CLI をインストールし、Kiro にコードベースをレビューさせたり、修正内容のサマリーを書かせたりなど、Kiro を CI/CD パイプラインの一部として簡単に組み込めるようになりました。

さて、この記事では Kiro CLI を Lambda で動作させる方法について、実際に検証して試していきたいと思います。

前提条件

本記事では以下の環境を前提として検証を実施しました。

  • AWS リージョン: us-east-1
    • 本検証では便宜上、全リソースを us-east-1 リージョンに配置します。実運用ではリソース個別に利用可能リージョンをご確認ください
  • Lambda ベースイメージ: public.ecr.aws/lambda/python:3.14 (執筆時点での最新版)
  • Kiro CLI: バージョン 2.1.1 (執筆時点での最新版)
  • ローカルビルド環境: MacOS (Apple Silicon) + Docker CLI + colima
  • Kiro API キーの発行が完了していること
    • Kiro Web に IAM Identity Center 経由でログインし、アカウント設定から API キーを発行する必要があります

関数作成

Kiro API キーを Secrets Manager に保存

まずは Kiro API キーを Secrets Manager シークレットに保存しておきます。API キーは長期間有効な認証情報ですので、必ず安全な場所に保管しておきましょう。くれぐれも Lambda のソースコード内にハードコードするのは絶対に避けてください。

aws secretsmanager create-secret \
  --name kiro-credentials \
  --region us-east-1 \
  --secret-string '{"KIRO_API_KEY":"ksk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}'

コンテナイメージ作成の準備

次に Kiro CLI を載せた Lambda 関数を作成します。

Lambda 関数はソースコードを ZIP ファイルに固めてアップするか、コンテナイメージとしてビルドしてデプロイするかの 2 通りの作成方法がありますが、Kiro CLI のファイルサイズがクォータを超過することから前者の方法は取れません。
そのため、今回はコンテナイメージを作成してデプロイする方法で進めていきます。はじめに、ディレクトリ構成を以下のように作成しておきます。

lambda-image/
├── Dockerfile
├── handler.py
└── .dockerignore

次に Dockerfile を以下のように作成しておきます。

ベースイメージには Python 3.14 ベースのものを選択しました。言語環境はあまり問わないとは思いますが、バージョンは Kiro CLI が glibc 2.34 以上を要求するため Amazon Linux 2023 がベースになっているものを選択されるのが良いかと思います。
あとは公式ドキュメントに記載されている インストールコマンド の実行や、依存ファイルの設定等を含むのみで、必要な設定はシンプルです。

FROM public.ecr.aws/lambda/python:3.14

RUN dnf install -y unzip ca-certificates && dnf clean all

ENV HOME=/opt/kiro-home
RUN mkdir -p $HOME && \
    curl -fsSL https://cli.kiro.dev/install | bash

RUN pip install --no-cache-dir boto3

COPY handler.py ${LAMBDA_TASK_ROOT}/

ENV HOME=/tmp \
    PATH=/opt/kiro-home/.local/bin:${PATH}

CMD ["handler.handler"]

Lambda 関数のソースコードは以下のものを設定しました。
Secrets Manager から Kiro API キーを取得して、subprocess で Kiro CLI のバイナリを呼び出すだけのシンプルな作りになっています。

ポイントは --no-interactive オプションをつけることで、非対話的な実行モードになり Lambda 関数内のようなユーザーとの対話を行わない環境下でも自律的に動作します。
また、 --trust-all-tools オプションをつけることですべてのツール実行を許可したり、 --trust-tools で部分的に許可したりといったことも可能です。詳細は Kiro CLI のドキュメント をご覧ください。いずれにせよ、オプションに関しては、Lambda 関数で Kiro CLI を動かすにあたって --no-interactive が実質的に必須となることを除き、通常のローカル環境での実行時と使い方に差異はないかと思います。

もう一つのポイントとして、Kiro が標準出力や標準エラーに出力する文字列には、CLI で文字に色を付けて表示するための ANSI エスケープシーケンスが含まれます。
そのため、ANSI エスケープシーケンスを除去しないと、例えば出力を後続処理でプログラム的に扱いたい場合にノイズとなってしまう点が挙げられます。 (例: \x1b[38;5;141m> \x1b[0mI )
公式ドキュメント には NO_COLORKIRO_LOG_NO_COLOR の環境変数で無効化できるとの記述があるのですが、実際には制御文字が残ってしまっていたため、正規表現で ANSI エスケープシーケンスを除く処理を追加しました。

import json
import re
import os
import subprocess
import boto3

KIRO_BIN = "/opt/kiro-home/.local/bin/kiro-cli"
SECRET_ID = os.environ.get("KIRO_SECRET_ID", "kiro-credentials")
SECRET_REGION = os.environ.get("KIRO_SECRET_REGION", "us-east-1")

# ANSI エスケープシーケンスを除去する関数 (詳細は後述)
ANSI_ESCAPE_RE = re.compile(r'\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')

def _strip_ansi(s: str) -> str:
  return ANSI_ESCAPE_RE.sub("", s) if s else s

# Secrets Manager シークレットから Kiro API キーを取得する (キャッシュ付き)
_api_key_cache = None

def _get_api_key():
  global _api_key_cache
  if _api_key_cache:
    return _api_key_cache

  client = boto3.client("secretsmanager", region_name=SECRET_REGION)
  resp = client.get_secret_value(SecretId=SECRET_ID)
  secret = json.loads(resp["SecretString"])
  _api_key_cache = secret["KIRO_API_KEY"]
  return _api_key_cache

# メイン処理
def handler(event, context):
  prompt = event.get("prompt")
  trust_all_tools = event.get("trust_all_tools", True)

  env = os.environ.copy()
  env["KIRO_API_KEY"] = _get_api_key()
  env["HOME"] = "/tmp"
  env["NO_COLOR"] = "1"  # 色制御を抑止(TUI制御は別途regexで除去)

  cmd = [KIRO_BIN, "chat", "--no-interactive"]
  if trust_all_tools:
    cmd.append("--trust-all-tools")
  cmd.append(prompt)

  completed = subprocess.run(
    cmd,
    env=env,
    cwd="/tmp",
    capture_output=True,
    text=True,
    timeout=context.get_remaining_time_in_millis() / 1000 - 5,
  )
  return {
    "statusCode": 200 if completed.returncode == 0 else 500,
    "returncode": completed.returncode,
    "stdout": _strip_ansi(completed.stdout),
    "stderr": _strip_ansi(completed.stderr),
  }

.dockerignore は以下を書いておきます。

*
!Dockerfile
!handler.py

以上で準備は完了です。

コンテナイメージの作成

あとはサクサクと作成したファイルをもとにビルドとプッシュを行うのみです。

# リポジトリ作成 ※初回のみ
aws ecr create-repository \
  --repository-name "{リポジトリ名}" \
  --region "us-east-1" \
  --image-scanning-configuration scanOnPush=true \
  --encryption-configuration encryptionType=AES256

# ECR ログイン ※初回のみ
aws ecr get-login-password --region "us-east-1" \
  | docker login --username AWS --password-stdin "{AWSアカウントID}.dkr.ecr.us-east-1.amazonaws.com"

# ビルド
docker buildx build \
  --platform linux/amd64 \
  --provenance=false \
  -t kiro-on-lambda:latest \
  --load .

# タグ付け & プッシュ
docker tag kiro-on-lambda:latest "{AWSアカウントID}.dkr.ecr.us-east-1.amazonaws.com/{リポジトリ名}:v1"
docker push "{AWSアカウントID}.dkr.ecr.us-east-1.amazonaws.com/{リポジトリ名}:v1"

Lambda 関数実行用 IAM ロール作成

今回は CLI から Lambda 関数を作成するので、IAM ロールも CLI から手動で作成します。
信頼ポリシーには lambda.amazonaws.com からの呼び出しを許可し、 AWSLambdaBasicExecutionRole ポリシーをアタッチしておきます。

cat > lambda-trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "lambda.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

aws iam create-role \
  --role-name kiro-on-lambda-role \
  --assume-role-policy-document file://lambda-trust-policy.json

aws iam attach-role-policy \
  --role-name kiro-on-lambda-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

許可ポリシーには、Secrets Manager シークレットからの Kiro API キーの取得を許可しておきます。

cat > lambda-inline-policy.json <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["secretsmanager:GetSecretValue"],
      "Resource": "arn:aws:secretsmanager:us-east-1:${AWSアカウントID}:secret:kiro-credentials*"
    }
  ]
}
EOF

aws iam put-role-policy \
  --role-name kiro-on-lambda-role \
  --policy-name ReadKiroSecret \
  --policy-document file://lambda-inline-policy.json

Lambda 関数の作成

先ほど作成しプッシュしたコンテナイメージと実行ロールを指定して関数を作成します。

aws lambda create-function \
  --function-name kiro-on-lambda \
  --region "us-east-1" \
  --package-type Image \
  --code "ImageUri={AWSアカウントID}.dkr.ecr.us-east-1.amazonaws.com/{リポジトリ名}:v1" \
  --role "arn:aws:iam::{AWSアカウントID}:role/kiro-on-lambda-role" \
  --timeout 300 \
  --memory-size 2048 \
  --ephemeral-storage Size=1024 \
  --architectures x86_64 \
  --description "Kiro CLI on Lambda"

タイムアウト時間はコールドスタートの起動時間や Kiro がプロンプトを処理するのに掛かる時間を考慮してやや長め (300 秒) の設定にしました。また、エフェメラルストレージのサイズは、Kiro CLI のインストールに必要な領域として数百 MB 程度が必要であったため、余裕をもって 1024 MB に、メモリサイズは何度か実測したところ最大 350 MB 程度であったため、余裕をもたせて 2048 MB としています。実運用に際してはさらに慎重なパラメータ調整が必要かとは思いますが、ご参考になりましたら幸いです。

動作確認

以下のように CLI から Lambda 関数を起動して結果を確認してみます。

aws lambda invoke \
  --cli-binary-format raw-in-base64-out \
  --function-name kiro-on-lambda \
  --region us-east-1 \
  --payload '{"prompt":"Hello from AWS Lambda. Please introduce yourself in one sentence."}' \
  out.json

cat out.json | jq -r '.stdout'

以下のように Kiro が生成した文字列が返却されており、動作確認ができました。

> Hi! I'm Kiro, an AI agent that helps with coding, writing, analysis, research,
  and other professional tasks — ready to assist with whatever you need.

writeread ツールを使って、 /tmp 配下のファイルにアクセスさせることも試してみます。
Kiro にファイルを作成させ、再び読ませて出力させるようプロンプトで指示し、関数を実行してみることにします。
このとき、Kiro が実際にはファイルを作成していないにもかかわらず作成したかのように生成してしまう (ハルシネーション) と、実際のツール利用を検証できないため、関数側のプログラムにファイル出力結果を確かめるコードを追記しておきます。

+ verifications = []
+ for p in event.get("verify_paths", []):
+   item = {"path": p, "exists": os.path.exists(p)}
+   if item["exists"]:
+     try:
+       item["size"] = os.path.getsize(p)
+       with open(p) as f:
+         item["content"] = f.read()[:500]
+     except Exception as e:
+       item["error"] = repr(e)
+   verifications.append(item)

return {
  "statusCode": 200 if completed.returncode == 0 else 500,
  "returncode": completed.returncode,
  "stdout": _strip_ansi(completed.stdout),
  "stderr": _strip_ansi(completed.stderr),
  "cmd": cmd[:-1] + ["<prompt>"],
+   "verifications": verifications,
}
aws lambda invoke \
  --cli-binary-format raw-in-base64-out \
  --function-name kiro-on-lambda \
  --region us-east-1 \
  --payload '{
    "prompt":"Use the fs_write tool to create /tmp/hello.txt containing exactly the text \"Hello from Lambda\", then use fs_read to read it back and report the content.",
    "verify_paths":["/tmp/hello.txt"]
  }' \
  out.json

cat out.json | jq '.verifications'

実際の応答は以下となり、Kiro が Hello from Lambda という文字列を /tmp/hello.txt にツール経由で出力できていることが確認できました。

[
  {
    "path": "/tmp/hello.txt",
    "exists": true,
    "size": 18,
    "content": "Hello from Lambda\n"
  }
]

さいごに

この記事では Lambda 上で Kiro CLI を動作させるための方法についてご紹介しました。
AWS 公式ブログ にも紹介があるような、ドキュメント生成、依存関係の監査、PR サマリー等の用途で Kiro を利用することができ、さらに Kiro の活用の幅を広げることができるかと思います。

また、弊社でも Kiro CLI の subagent 機能や hook 機能を組み合わせた、ノーコードな業務支援ツールを開発中であり、そのプロンプトを動作させるための基盤としてこの仕組みを応用しています。
Kiro は開発支援のための IDE としてだけでなく、ノーコード / ローコードなエージェントワークフローツールとしても利用でき、開発や業務への応用の幅が広がるのではないでしょうか。

本記事の内容が少しでも皆さまの生成 AI 活用の一助になりましたら幸いです。
最後までお読みいただきありがとうございました。

参考記事

クラスメソッドオペレーションズ株式会社について

クラスメソッドグループのオペレーション企業です。

運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AIをフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。

当社は様々な職種でメンバーを募集しています。

「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 採用サイト をぜひご覧ください。※2026年1月 アノテーション㈱から社名変更しました

この記事をシェアする

関連記事