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

Claude Code × AWS IAMガイド:最小権限ポリシーを安全に作る実践手順

Claude CodeでAWS IAM最小権限を設計・検証する実践ガイド。Access AnalyzerとCDK例つき。

Claude Code × AWS IAMガイド:最小権限ポリシーを安全に作る実践手順

AWS IAMは、AWSの「誰が、どのリソースに、何をしてよいか」を決める権限の仕組みです。画面では小さなJSONに見えますが、Action: "*"Resource: "*"を雑に許すと、S3の削除、DynamoDBの読み出し、Lambdaの更新まで一気に広がります。Claude Codeに丸投げして「動いたからOK」にすると、便利な自動化がそのまま本番事故の入口になります。

この記事では、Claude CodeをAWS IAMポリシー作成の相棒として使いながら、最小権限を崩さない手順をまとめます。最小権限とは「必要な操作を、必要な対象にだけ許す」考え方です。ポリシーは権限ルール、ロールは一時的に引き受ける役割、プリンシパルは権限を使うユーザーやサービスだと考えると、初心者でも理解しやすくなります。

Masaが実案件で一番失敗したのは、Lambdaの実行ロールに一時的なつもりで広いS3権限を付け、そのまま数週間残したことです。幸い外部流出はありませんでしたが、レビューで見つかった時点で「Claude Codeに出させたポリシーを人間がAWS公式の観点で検証する」流れに変えました。現在は、Claude Codeで下書き、IAM Access Analyzerで検証、人間が差分をレビュー、CDKで固定、拒否されるべき操作もテスト、という順番にしています。

公式ドキュメントを基準にする

IAMは検索記事だけで判断すると危険です。この記事の方針は、次のAWS公式ドキュメントに合わせています。

要点は明確です。人間ユーザーは長期アクセスキーではなくフェデレーションや一時認証情報を使う。ワークロードはIAMロールを使う。権限は最小化する。Access Analyzerでポリシーを検証する。未使用のユーザー、ロール、権限、認証情報を定期的に削除する。この5つをClaude Codeのプロンプトにも明記します。

flowchart LR
  A["ユースケースを文章化"] --> B["Claude Codeで下書き"]
  B --> C["人間がリソース名を確認"]
  C --> D["IAM Access Analyzerで検証"]
  D --> E["CDKでコード化"]
  E --> F["許可と拒否の両方をテスト"]

先にユースケースを固定する

Claude Codeに「IAMポリシーを書いて」とだけ頼むと、足りない情報を広めの権限で埋めがちです。先に、どの実行主体が、どのAWSサービスに、どの操作だけを行うのかを書きます。

ユースケース実行主体必要な権限明示して避ける権限
画像サムネイル生成LambdaLambda実行ロールS3読み取り、S3書き込み、DynamoDB書き込み、SNS通知、ログ出力S3削除、全バケット読み取り、IAM操作
管理画面のアップロード補助API用Lambdaロール特定prefixへのS3 PutObject、DynamoDB GetItemバケット全体のList、KMSキー管理
GitHub ActionsからのデプロイOIDCで引き受けるCIロール1つのCloudFormationスタック更新、対象Lambda更新AdministratorAccess、全リージョン操作
障害調査用の読み取りロールフェデレーションユーザーCloudWatch Logs検索、X-Ray参照、該当テーブルのGetItem更新、削除、Secret取得

この表をプロンプトに含めるだけで、Claude Codeの出力はかなり現実的になります。特に「明示して避ける権限」を書くのが重要です。生成AIは必要権限の列は拾いますが、禁止したい操作は言わないと推測しません。

コピペで使えるLambda実行ポリシー

次の例は、画像をS3から読み、サムネイルを別バケットへ保存し、DynamoDBへ結果を書き、失敗時にSNSへ通知するLambda用です。ロググループはCDKやCloudFormationで事前作成する前提にして、実行ロールにはlogs:CreateLogGroupを渡していません。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadSourceImages",
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::user-uploads-prod/incoming/*"
    },
    {
      "Sid": "WriteThumbnails",
      "Effect": "Allow",
      "Action": ["s3:PutObject"],
      "Resource": "arn:aws:s3:::user-thumbnails-prod/thumbnails/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-server-side-encryption": "AES256"
        }
      }
    },
    {
      "Sid": "WriteMetadata",
      "Effect": "Allow",
      "Action": ["dynamodb:PutItem", "dynamodb:UpdateItem"],
      "Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/image-metadata"
    },
    {
      "Sid": "PublishAlerts",
      "Effect": "Allow",
      "Action": ["sns:Publish"],
      "Resource": "arn:aws:sns:ap-northeast-1:123456789012:alert-topic"
    },
    {
      "Sid": "WriteLambdaLogs",
      "Effect": "Allow",
      "Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
      "Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/image-worker-prod:*"
    }
  ]
}

このJSONをpolicy-lambda-image-worker.jsonとして保存し、構文とAWSベストプラクティスの警告を確認します。

aws accessanalyzer validate-policy \
  --policy-document file://policy-lambda-image-worker.json \
  --policy-type IDENTITY_POLICY \
  --query "findings[?findingType!='SUGGESTION']"

Access Analyzerは万能な承認者ではありません。AWS公式の説明どおり、文法、ARN、アクション名、条件キー、セキュリティ警告を確認する道具です。業務上その操作が本当に必要か、アカウントIDやバケット名が本番と一致しているか、削除権限が混ざっていないかは人間が見ます。

Claude Codeには次のようにレビューさせます。

claude -p "policy-lambda-image-worker.jsonをAWS IAMの最小権限としてレビューしてください。
前提: LambdaはS3 incoming/を読み、thumbnails/へ書き、DynamoDB table image-metadataへPutItem/UpdateItemし、SNS alert-topicへPublishします。
確認観点: ワイルドカード、削除権限、Resourceの広すぎ、Conditionの妥当性、CloudWatch Logsの範囲。
出力: Sidごとに risk / reason / safer fix を表にしてください。"

CDKでロールを固定する

手作業でIAMコンソールを直すと、レビュー済みの状態が残りません。TypeScript CDKなら、ロール、ロググループ、ポリシーを同じPull Requestで確認できます。以下はlib/image-worker-iam-stack.tsとして使える最小構成です。

import * as cdk from "aws-cdk-lib";
import { Stack, StackProps, aws_iam as iam, aws_logs as logs } from "aws-cdk-lib";
import { Construct } from "constructs";

export class ImageWorkerIamStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const account = Stack.of(this).account;
    const region = Stack.of(this).region;

    new logs.LogGroup(this, "ImageWorkerLogGroup", {
      logGroupName: "/aws/lambda/image-worker-prod",
      retention: logs.RetentionDays.ONE_MONTH,
      removalPolicy: cdk.RemovalPolicy.RETAIN,
    });

    const role = new iam.Role(this, "ImageWorkerRole", {
      assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
      description: "Execution role for image-worker-prod Lambda",
    });

    role.addToPolicy(new iam.PolicyStatement({
      sid: "ReadSourceImages",
      actions: ["s3:GetObject"],
      resources: ["arn:aws:s3:::user-uploads-prod/incoming/*"],
    }));

    role.addToPolicy(new iam.PolicyStatement({
      sid: "WriteThumbnails",
      actions: ["s3:PutObject"],
      resources: ["arn:aws:s3:::user-thumbnails-prod/thumbnails/*"],
      conditions: {
        StringEquals: {
          "s3:x-amz-server-side-encryption": "AES256",
        },
      },
    }));

    role.addToPolicy(new iam.PolicyStatement({
      sid: "WriteMetadataAndAlerts",
      actions: ["dynamodb:PutItem", "dynamodb:UpdateItem", "sns:Publish"],
      resources: [
        `arn:aws:dynamodb:${region}:${account}:table/image-metadata`,
        `arn:aws:sns:${region}:${account}:alert-topic`,
      ],
    }));

    role.addToPolicy(new iam.PolicyStatement({
      sid: "WriteLambdaLogs",
      actions: ["logs:CreateLogStream", "logs:PutLogEvents"],
      resources: [
        `arn:aws:logs:${region}:${account}:log-group:/aws/lambda/image-worker-prod:*`,
      ],
    }));
  }
}

この例は「広い権限を付けて後で削る」作り方ではありません。最初から対象prefix、対象テーブル、対象トピック、対象ロググループを指定します。CloudWatch LogsのためだけにAWS管理ポリシーを付けると便利ですが、複数Lambdaで同じ運用にしたい場合は、上のように明示したほうがレビューしやすくなります。

CIロールは長期キーではなくOIDCにする

Claude CodeをCI/CDにも使う場合、GitHub Actionsのシークレットに長期アクセスキーを置く設計は避けます。AWS公式のIAMベストプラクティスは、一時認証情報とロール利用を重視しています。GitHub ActionsならOIDCでAWSロールを引き受ける構成にします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:example-org/example-repo:ref:refs/heads/main"
        }
      }
    }
  ]
}

これは信頼ポリシーです。信頼ポリシーは「誰がロールを引き受けられるか」を決めます。一方、権限ポリシーは「引き受けた後に何ができるか」を決めます。この2つを混ぜると、レビューが急に難しくなります。Claude Codeへの依頼も「信頼ポリシーを見て」「権限ポリシーを見て」と分けます。

よくある落とし穴

1つ目は、Action: "*"を一時対応として入れることです。一時対応は本番では恒久化しがちです。どうしても緊急対応が必要なら、期限付きチケット、CloudTrail確認、削除予定日、Access Analyzerの再実行を同じ作業ログに残します。

2つ目は、S3のARNを間違えることです。s3:ListBucketarn:aws:s3:::bucket-nameに付け、s3:GetObjects3:PutObjectarn:aws:s3:::bucket-name/prefix/*に付けます。ここを混ぜると、動かないか、広すぎる権限になります。

3つ目は、Lambda実行ロールへIP制限を雑に入れることです。人間がコンソールから呼ぶAPIと、AWSサービスがロールを使って呼ぶAPIでは条件キーの意味が違います。aws:SourceIpで社内IPに絞れば安全に見えますが、LambdaやAWSサービス間呼び出しでは期待どおり動かないことがあります。

4つ目は、拒否されるべき操作をテストしないことです。s3:GetObjectが成功するかだけを見ると、s3:DeleteObjectまで通る事故に気づけません。権限テストでは、成功パスと失敗パスを両方確認します。

5つ目は、Claude Codeの説明を公式仕様の代わりにすることです。Claude Codeはレビュー観点の列挙や差分検出に強い一方、最新のIAM仕様、サービス別のリソースレベル権限、条件キーの対応状況は公式ドキュメントとAccess Analyzerで確認する必要があります。

運用レビューの型

Pull Requestでは、ポリシー本文だけでなく、次のチェックリストをコメントに貼ります。

  • このロールを使う実行主体は1つに絞れているか
  • Actionに削除、IAM管理、全サービス操作が混ざっていないか
  • Resourceが本番のARN、prefix、リージョン、アカウントIDに固定されているか
  • Conditionはサービスの呼び出し方に合っているか
  • Access AnalyzerのSECURITY_WARNINGERRORが残っていないか
  • CloudTrailやCloudWatch Logsで実際のアクセス履歴を後から見直せるか
  • 30日後に未使用権限を削るチケットを作ったか

IAMは一度作って終わりではありません。新機能追加、障害対応、外部連携、担当者交代のたびに権限は太ります。定期的な棚卸しは地味ですが、AdSense向けの技術記事と同じで、信頼を積み上げる作業です。

関連して読む記事

Lambdaの実行ロール設計はAWS Lambda完全ガイド、S3のprefix設計はAWS S3入門、ログ監査はAWS CloudWatch活用、全体の安全設計はClaude Codeセキュリティ実践と合わせて読むとつながります。

チームでClaude CodeとAWS権限設計を標準化したい場合は、Claude Code研修・導入相談で、既存リポジトリのIAM、CDK、CI権限、レビュー手順を題材に整理できます。個人で始めるなら無料チートシートを手元に置き、繰り返し使うレビュー文面やCLAUDE.mdは商品一覧から選ぶ流れが実用的です。

この記事で紹介した内容を実際に試した結果、Claude Codeだけでポリシーを作った時より、最初にユースケース表を書くほうが修正回数は明らかに減りました。特に「禁止する操作」をプロンプトに含めると、DeleteObjectや広いlogs:*が混ざる頻度が下がります。最後にAccess Analyzerと拒否テストを入れると、安心感ではなく証拠を持ってレビューできるようになりました。

#claude-code #aws #iam #security #typescript #infrastructure
無料

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

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

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

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

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

Masa

この記事を書いた人

Masa

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

PR

関連書籍・参考図書

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

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