Use Cases (更新: 2026/6/1)

Claude CodeでAWS Lambdaを安全に作る実践ガイド

Node.js LambdaをClaude Codeで作り、ローカルテスト、IAM、環境変数、API Gateway、ログ確認まで安全に進める手順。

Claude CodeでAWS Lambdaを安全に作る実践ガイド

AWS LambdaをClaude Codeで書くと、ハンドラー、テストイベント、IAMポリシー、デプロイコマンドまで一気に形になります。便利な一方で、AWSは権限と課金が本番に直結します。Claude Codeに任せてよいのは下書きと確認の自動化までで、実際の権限付与、公開API、削除できないリソース、月額コストは必ず人間がレビューします。

この記事では、チームで使いやすい最小構成として、Node.jsのLambdaを作り、ローカルで動作確認し、IAMを最小権限に近づけ、環境変数、CloudWatch Logs、API Gateway、zipパッケージでの更新まで進めます。Lambdaは「イベントを受け取ったときだけ起動する小さな実行環境」、IAMは「AWSで何をしてよいかを決める権限表」、API Gatewayは「HTTPリクエストをLambdaへ渡す入口」です。

公式仕様は変わるので、実装前にAWS Lambdaの入門ドキュメントNode.js Lambdaの公式ガイド環境変数の公式ガイドCloudWatch Logsでの監視、そしてClaude Codeのcommon workflowsを横に置いてください。この記事は2026年6月1日時点で、Node.js 24ランタイムを前提にしています。

どんな場面で使うか

Lambdaは「ずっとサーバーを動かすほどではないが、確実に処理したい」作業に向いています。Claude Codeと相性がよいユースケースは次の3つです。

ユースケースLambdaでやる理由Claude Codeに任せる範囲人間が見る範囲
Webhook受信決済、フォーム、SaaS通知を短時間で受けられる署名検証、イベントfixture、失敗時レスポンスの下書き秘密鍵の扱い、リトライ、重複処理
社内用の軽いAPI小さなJSON APIなら常時稼働サーバーが不要Node.js handler、API Gateway接続、ログ設計認証、CORS、公開範囲、コスト
バッチの入口CSV投入、画像処理、通知キューなどを小さく始められる入力チェック、CloudWatchログ、エラー分類タイムアウト、再実行、安全な削除

比較すると、最初の検証はzipデプロイが速く、チーム運用はSAMやCDKに移すのが現実的です。

方法向いている場面注意点
AWSコンソール1回だけ挙動を見る手順が残らず、レビューしにくい
AWS CLI + zipこの記事のような小さい検証IAMと環境変数を手で確認する必要がある
SAM / CDKチームの継続運用IaCのレビューとデプロイ承認が必要

概念図にすると、Claude Codeはコードを書く人ではなく、レビュー材料をそろえる補助役です。

flowchart LR
  A[Claude Codeで下書き] --> B[ローカルNode.jsテスト]
  B --> C[IAMと環境変数を人間が確認]
  C --> D[zipパッケージをdevへデプロイ]
  D --> E[API Gateway経由で確認]
  E --> F[CloudWatch Logsで失敗を読む]
  F --> A

1. Node.js Lambdaハンドラー

まず依存パッケージなしで動くindex.mjsを作ります。API Gateway HTTP APIのイベントと、古いREST API形式のどちらでも動くように、rawPathpathrequestContext.http.methodhttpMethodの両方を見ます。

// index.mjs
import crypto from "node:crypto";

const allowedStages = new Set(["dev", "staging", "prod"]);

function readConfig() {
  const stage = process.env.APP_STAGE ?? "dev";
  if (!allowedStages.has(stage)) {
    throw new Error(`Invalid APP_STAGE: ${stage}`);
  }

  return {
    stage,
    tableName: process.env.TABLE_NAME ?? "local-orders",
    logLevel: process.env.LOG_LEVEL ?? "info",
  };
}

function log(level, message, details = {}) {
  console.log(
    JSON.stringify({
      level,
      message,
      service: "orders-api",
      ...details,
    })
  );
}

function json(statusCode, body) {
  return {
    statusCode,
    headers: {
      "content-type": "application/json",
    },
    body: JSON.stringify(body),
  };
}

function parseBody(event) {
  if (!event.body) return {};
  const raw = event.isBase64Encoded
    ? Buffer.from(event.body, "base64").toString("utf8")
    : event.body;
  return JSON.parse(raw);
}

export async function handler(event = {}, context = {}) {
  const config = readConfig();
  const method = event.requestContext?.http?.method ?? event.httpMethod ?? "GET";
  const path = event.rawPath ?? event.path ?? "/";
  const requestId = context.awsRequestId ?? "local";

  log("info", "request.start", {
    requestId,
    method,
    path,
    stage: config.stage,
  });

  try {
    if (method === "GET" && path === "/health") {
      return json(200, { ok: true, stage: config.stage });
    }

    if (method === "POST" && path === "/orders") {
      const payload = parseBody(event);
      const orderId = payload.orderId ?? crypto.randomUUID();

      log("info", "order.accepted", {
        requestId,
        orderId,
        tableName: config.tableName,
      });

      return json(202, {
        orderId,
        status: "accepted",
        storedIn: config.tableName,
      });
    }

    return json(404, { error: "not_found", method, path });
  } catch (error) {
    log("error", "request.failed", {
      requestId,
      errorName: error.name,
      errorMessage: error.message,
    });

    return json(500, { error: "internal_error", requestId });
  }
}

この段階ではDynamoDBに書き込んでいません。初心者が最初にやるべきことは「HTTPイベントを正しく受け取る」「JSONを返す」「ログで追える」状態を作ることです。データベース接続を後から足すほうが、権限と失敗原因を切り分けやすくなります。

2. イベントfixtureでローカルテストする

次に、API Gatewayから来るイベントをJSONで保存します。fixtureは「テスト用の固定入力」です。Claude Codeに生成させるときも、実リクエストの形に近いfixtureを残すとレビューしやすくなります。

{
  "version": "2.0",
  "routeKey": "POST /orders",
  "rawPath": "/orders",
  "requestContext": {
    "http": {
      "method": "POST",
      "path": "/orders"
    }
  },
  "headers": {
    "content-type": "application/json"
  },
  "body": "{\"orderId\":\"demo-1001\",\"amount\":3200,\"currency\":\"JPY\"}",
  "isBase64Encoded": false
}

events/create-order.jsonとして保存したら、ローカル実行用の小さなスクリプトを作ります。

// local-test.mjs
import { readFile } from "node:fs/promises";
import { handler } from "./index.mjs";

process.env.APP_STAGE = "dev";
process.env.TABLE_NAME = "orders-dev";
process.env.LOG_LEVEL = "debug";

const eventPath = process.argv[2] ?? "events/create-order.json";
const event = JSON.parse(await readFile(eventPath, "utf8"));

const result = await handler(event, { awsRequestId: "local-001" });
console.log(JSON.stringify(result, null, 2));

実行します。

node local-test.mjs events/create-order.json

期待する出力はstatusCode202で、orderIdが返ることです。ここで動かないものはAWSに上げても直りません。Claude Codeに「このログと出力を見て、原因候補を3つに絞って」と頼む前に、まずローカルで再現できる入力を作るのが近道です。

3. IAMは最小権限から始める

Lambda実行ロールには、最初からAdministratorAccessを付けません。CloudWatch Logsへの出力だけなら、次のような権限から始めます。DynamoDBを使う場合だけ、対象テーブルのARNに絞って追加します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CreateOwnLogGroupIfMissing",
      "Effect": "Allow",
      "Action": "logs:CreateLogGroup",
      "Resource": "arn:aws:logs:ap-northeast-1:123456789012:*"
    },
    {
      "Sid": "WriteOwnLambdaLogs",
      "Effect": "Allow",
      "Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
      "Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/claude-orders-dev:*"
    },
    {
      "Sid": "ReadWriteOnlyOrdersTable",
      "Effect": "Allow",
      "Action": ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:Query"],
      "Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/orders-dev"
    }
  ]
}

このJSONはそのまま本番へ貼るものではなく、レビューのたたき台です。アカウントID、リージョン、関数名、テーブル名を実環境に合わせ、使っていないDynamoDB権限は削ってください。IAMの変更は「通るか」ではなく「広すぎないか」を人間が確認します。AWS権限の考え方は、サイト内のAWS IAMガイドも参考になります。

4. zipパッケージでデプロイする

ここからはAWS CLIを使います。実行するとAWSリソースが作られ、少額でも課金対象になる可能性があります。作業前にAWSアカウント、リージョン、削除手順を確認してください。

export AWS_REGION=ap-northeast-1
export FUNCTION_NAME=claude-orders-dev
export ROLE_NAME=claude-orders-dev-lambda-role
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

zip function.zip index.mjs

信頼ポリシーを作ります。これは「Lambdaサービスがこのロールを引き受けてよい」という設定です。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

trust-policy.jsonとして保存したら、ロールを作成します。さきほどのIAMポリシーはlambda-policy.jsonとして保存しておきます。

aws iam create-role \
  --role-name "$ROLE_NAME" \
  --assume-role-policy-document file://trust-policy.json

aws iam put-role-policy \
  --role-name "$ROLE_NAME" \
  --policy-name claude-orders-dev-inline \
  --policy-document file://lambda-policy.json

ROLE_ARN=$(aws iam get-role \
  --role-name "$ROLE_NAME" \
  --query "Role.Arn" \
  --output text)

aws lambda create-function \
  --function-name "$FUNCTION_NAME" \
  --runtime nodejs24.x \
  --handler index.handler \
  --zip-file fileb://function.zip \
  --role "$ROLE_ARN" \
  --architectures arm64 \
  --timeout 10 \
  --memory-size 128 \
  --environment "Variables={APP_STAGE=dev,TABLE_NAME=orders-dev,LOG_LEVEL=info}" \
  --region "$AWS_REGION"

コードだけ更新するときは、関数を作り直さずに次のコマンドを使います。

zip function.zip index.mjs

aws lambda update-function-code \
  --function-name "$FUNCTION_NAME" \
  --zip-file fileb://function.zip \
  --region "$AWS_REGION"

環境変数を更新するときは注意が必要です。AWS CLIのupdate-function-configurationで環境変数を指定すると、既存のVariables全体を置き換える挙動になります。差分だけを追加するつもりで既存値を消さないよう、現在値を取得してから変更してください。パスワードやAPIキーのような秘密情報は環境変数に直接入れず、Secrets ManagerやParameter Storeを検討します。

aws lambda update-function-configuration \
  --function-name "$FUNCTION_NAME" \
  --environment "Variables={APP_STAGE=dev,TABLE_NAME=orders-dev,LOG_LEVEL=debug}" \
  --region "$AWS_REGION"

5. API GatewayとCloudWatch Logsで確認する

まずLambdaを直接呼び出します。

aws lambda invoke \
  --function-name "$FUNCTION_NAME" \
  --payload fileb://events/create-order.json \
  --region "$AWS_REGION" \
  response.json

cat response.json

次にHTTP APIを作り、Lambdaへつなぎます。公開URLができます。社内検証でも、認証、CORS、レート制限、削除予定日を確認してから実行してください。

API_ID=$(aws apigatewayv2 create-api \
  --name claude-orders-dev-api \
  --protocol-type HTTP \
  --target "arn:aws:lambda:${AWS_REGION}:${ACCOUNT_ID}:function:${FUNCTION_NAME}" \
  --query "ApiId" \
  --output text)

aws lambda add-permission \
  --function-name "$FUNCTION_NAME" \
  --statement-id AllowHttpApiInvoke \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:${AWS_REGION}:${ACCOUNT_ID}:${API_ID}/*/*" \
  --region "$AWS_REGION"

API_ENDPOINT=$(aws apigatewayv2 get-api \
  --api-id "$API_ID" \
  --query "ApiEndpoint" \
  --output text)

curl -s "$API_ENDPOINT/health"
curl -s -X POST "$API_ENDPOINT/orders" \
  -H "content-type: application/json" \
  -d '{"amount":3200,"currency":"JPY"}'

CloudWatch Logsは、障害対応の最初に見ます。console.logをJSONにしておくと、後から検索しやすくなります。

aws logs tail "/aws/lambda/${FUNCTION_NAME}" \
  --follow \
  --region "$AWS_REGION"

ログが出ない場合は、IAMのlogs:CreateLogStreamlogs:PutLogEvents、関数名、リージョンを確認します。API Gatewayで500になる場合は、Lambdaの戻り値がstatusCodeheadersbodyの形になっているかを見ます。より詳しい監視設計はAWS CloudWatchの記事AWS API Gatewayの記事も併読してください。

Claude Codeにレビューさせるプロンプト

Claude Codeには、自由にAWSへデプロイさせるのではなく、差分とリスクを説明させます。次のプロンプトをリポジトリで使うと、チームレビューに必要な観点がそろいます。

You are reviewing a Node.js AWS Lambda change for a team repository.

Scope:
- Files: index.mjs, events/*.json, IAM policy JSON, deployment commands in docs
- Runtime: nodejs24.x
- Entry point: index.handler

Review for:
1. API Gateway event compatibility and response shape
2. Input validation and JSON parsing failures
3. Environment variables that overwrite existing values
4. IAM actions that are wider than needed
5. CloudWatch logs that expose secrets or personal data
6. AWS resources that can create unexpected cost
7. Local test commands that a reviewer can copy and run

Return:
- blocking issues
- non-blocking improvements
- exact commands to verify locally
- questions a human must answer before deploying

ここで大事なのは、Claude Codeに「修正して」だけで頼まないことです。まず調査、計画、編集、検証の順に進めます。公式のcommon workflowsにあるように、探索してから実装させると、勝手な前提でIAMやデプロイ先を広げる失敗が減ります。

よくある落とし穴

1つ目は、ローカルで動かさずにAWSへ上げることです。LambdaのエラーはCloudWatch Logsに出ますが、イベントの形が違うだけならローカルfixtureで先に見つけられます。

2つ目は、環境変数に秘密情報を入れることです。Lambdaの環境変数は設定としては便利ですが、値の管理、暗号化、閲覧権限を考える必要があります。秘密情報はSecrets ManagerやParameter Storeを検討してください。

3つ目は、IAMを広げすぎることです。dynamodb:*Resource: "*"は検証を速くしますが、事故の範囲も広げます。Claude Codeが提案したポリシーは、使うアクションと対象ARNを1行ずつ削るレビューをします。

4つ目は、API Gatewayの公開範囲です。create-api --targetは素早い反面、公開URLがすぐできます。社内APIなら認証、CORS、ステージ名、ログ、レート制限、削除予定を先に決めます。

5つ目は、コストの見落としです。Lambda自体は小さく見えても、CloudWatch Logs、API Gateway、DynamoDB、NAT Gateway、外部API呼び出しで費用が増えます。Claude Codeの提案に「この構成で課金される箇所を列挙して」と必ず聞きます。

チーム導入時の安全なレビュー順

最初はdev環境だけで動かします。PRにはindex.mjs、fixture、IAMポリシー、デプロイ手順、削除手順を含めます。レビュー担当者はローカルでnode local-test.mjsを実行し、次にIAMの差分を読み、最後にAWS CLIのコマンドを確認します。

本番化するなら、zip手順をそのまま残すのではなく、AWSデプロイガイドのようにCI/CDやCDKへ移します。手作業のCLIは検証には向きますが、チーム運用では「誰が、いつ、何を変えたか」が残る仕組みが必要です。

ClaudeCodeLabでは、こうしたAWS権限、CLAUDE.md、レビュー用プロンプト、デプロイ承認の型を教材・テンプレートとして整理しています。自社のAWSアカウント構成、IAM境界、Lambda/API Gatewayのレビュー運用まで一緒に設計したい場合は、Claude Code導入相談・研修で実リポジトリ前提の相談ができます。

最後に削除手順も用意しておきます。検証後に不要なら、API、Lambda、IAMロールを消します。

aws apigatewayv2 delete-api --api-id "$API_ID" --region "$AWS_REGION"
aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$AWS_REGION"
aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name claude-orders-dev-inline
aws iam delete-role --role-name "$ROLE_NAME"

この記事で紹介した内容を実際に試した結果、Claude Codeは「handler、fixture、IAM、CLI手順を同じ文脈でそろえる」作業にかなり強い一方、AWS権限と公開URLの判断は人間が見ないと危険だと分かりました。ローカルfixtureで先に失敗を潰し、dev環境でログを読み、IAMとコストを人間が確認する順番にすると、Lambdaの小さな自動化でもチームで安心してレビューできます。

#Claude Code #AWS Lambda #サーバーレス #AWS #Node.js #IAM
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。