金色の配線パターンが広がる基板の接写
設計と運用

AWS Lambda の IAM 権限漏れをテストで防げない理由と検知の選び方

目次を見る

AWS Lambda(サーバーレス実行環境)のハンドラーに新しい処理を追加したあと、本番で突然 AccessDeniedException が出た経験がある方に向けた内容です。単体テストは通り、CI(継続的インテグレーション)も緑のまま、それでも本番で権限エラーが出るケースをどう防ぐか整理します。

注文処理の Lambda に「Secrets Manager(AWS のシークレット管理サービス)から Stripe の API キーを取得し、SNS(AWS のメッセージ通知サービス)に order.settled イベントを publish する」処理を追加する場面を考えます。AI コーディングアシスタントが書いたコードは綺麗で、SDK クライアントをモックした単体テストも通過します。ところが最初の本番実行で sns:Publish の AccessDeniedException が発生します。実行ロールが数か月前に DynamoDB 専用として書かれたままで、SNS への権限が追加されていなかったためです。

なぜテストもコードレビューもこの穴を見抜けないのか

この種の不具合が厄介なのは、開発ループ上のどのツールからも見えない位置にあるからです。

型チェッカーは PublishCommand が正しい型かどうかしか見ません。リンターも構文として正しい TypeScript を見るだけです。AI アシスタントはハンドラーのソースコードとインポート文までは読めますが、そのコードが実行時にどの IAM ロール(AWS のアクセス権限管理単位)で動くかは知りません。

ハンドラーと IAM ロールのつながりは、デプロイ済み関数の Role プロパティが ARN(AWS リソースを一意に指す識別子)を参照し、その ARN の先にポリシー文書がぶら下がるという構造です。リポジトリのファイルから数えて3段階も離れています。だからアシスタントは「権限はあるはず」という前提でコードを書くしかありません。9割はその前提が正しいので気づかれず、残り1割が本番障害として顕在化します。

この構造は Terraform や CloudFormation で IAM ポリシーを別ファイルに切り出している場合にも共通します。コードの変更とインフラ定義の変更が別のレビュー・別のタイミングで行われる限り、権限のドリフト(設定のずれ)は構造的に発生します。

判断軸

Lambda のような権限とコードが分離したアーキテクチャで、権限ドリフトをどう検知・防止するかを考えるときの軸を整理します。

検知タイミング: コーディング中・デプロイ前・本番実行時のどこで気づけるか。本番実行時に気づく設計はコストが最も高くなります。

静的解析の対象範囲: コードの AST(抽象構文木、プログラムの構造を木構造で表現したもの)を解析して DB アクセスや外部サービス呼び出しを検出する仕組みと、IAM ポリシーを実際に取得して照合する仕組みの両方が揃っているかどうかです。

誤検知への耐性: IAM 読み取りに失敗した場合や、ワイルドカード権限("Action": "*")が設定されている場合に、無理に判定を出さず沈黙する設計になっているかです。誤った警告を出し続けるツールは、やがて無視される運命にあります。

運用コスト: 同じロールを共有する関数が多い環境で、IAM の API 呼び出し回数がどれだけ増えるかも実務上は無視できません。

選択肢の比較

Lambda の権限ドリフトに対処する方法はいくつかあります。代表的な選択肢を整理します。

方法検知タイミングコード変更の要否弱点
手動レビューでIAMポリシーを都度確認デプロイ前不要レビュー漏れが常態化しやすい
IaC(Infrastructure as Code)でポリシーをコード管理デプロイ前不要(運用ルールの徹底が必要)コードとポリシーの変更タイミングがずれる
本番監視でAccessDeniedExceptionを検知本番実行時不要気づいたときには既に障害が起きている
コードとIAMを突合する静的解析ツール(例: infrawise)コーディング中〜デプロイ前不要(既存コードに対して解析を実行)マッピング対象のサービス種別が限定的

この中で、コードとIAMを突合する静的解析という考え方の具体例として、infrawise というツールの仕組みが参考になります。これはインフラとコードの両方をグラフ(依存関係の構造)として構築し、AST スキャンでハンドラーから DynamoDB や Secrets Manager、SNS/SQS への依存を型付きのエッジとして抽出します。同時に Lambda 関数の roleArn を取得し、そのロールに紐づく管理ポリシーとインラインポリシーをデコードして、許可されているサービスのプレフィックス一覧(allowedServices)を作ります。

たとえば sns:Publishsns に、dynamodb:GetItemdynamodb に単純化されます。あとはコードが要求するサービスと allowedServices を突き合わせ、差分があれば「コードは必要としているのに権限がない」項目として検出します。同じロールを共有する関数が10個あっても IAM への問い合わせは1回にまとめる設計になっており、API呼び出しコストへの配慮もされています。

重要なのは、この仕組みが誤検知を避ける方向に倒してある点です。IAM の読み取り自体が失敗した場合(権限不足や SCP による制限など)は判定を出さず、その関数の解析をスキップします。また "Action": "*" のようなワイルドカード権限を持つロールも対象外にします。過剰な権限を持つロールを検出することは、権限不足の検出とは別の問題として切り分けています。

ケース別の推奨

少人数チームで Lambda 関数が数個程度、IAM ポリシーの変更履歴も追いやすいなら、手動レビューとコードレビューのチェックリストに「新しい AWS サービス呼び出しを追加したら IAM ポリシーも確認する」という項目を足すだけでも一定の効果があります。

Lambda 関数が数十〜数百に増え、複数のチームがそれぞれ別のハンドラーを触っている状況なら、静的解析でコードとIAMの突合を自動化する方向が現実的です。人手でのレビューは関数数に比例してコストが増えますが、静的解析は関数数が増えても仕組み自体はスケールします。

AI コーディングアシスタントを日常的に使ってハンドラーの機能追加をしている場合は、特にこの種のツールの価値が上がります。アシスタントは権限を見ずにコードを書くため、生成されたコードとIAMの整合性チェックを人間かツールのどちらかが担う必要があるからです。

すでに IaC(Terraform や AWS CDK など)でロールを管理していて、コードとポリシーの変更を同じプルリクエストに含めるルールを徹底できているなら、追加ツールの優先度は下がります。ただしルールの徹底が形骸化しやすい点には注意が必要です。

あえて見送るべき条件

Lambda 関数の数が少なく、チームメンバー全員がすべての関数とロールの対応関係を把握できている場合は、静的解析ツールの導入コストが見合わないことがあります。

また IAM ポリシーが AdministratorAccess に近い広い権限を意図的に許容している開発環境(本番と分離されたサンドボックス環境など)では、権限不足の検知そのものが不要になります。この場合はむしろ権限が広すぎることの方が課題になるため、別の観点(最小権限の原則に基づく棚卸し)で対処するべきです。

AIアシスタントはコードは見えてもIAMポリシーは見えないため、権限ドリフトの検知はコードとIAMを別々に扱う限り構造的に漏れが生じます。

まとめ

Lambda の AccessDeniedException は、コードの品質問題ではなく、コードとIAMポリシーが別々のライフサイクルで管理されていることに起因する構造的な問題です。

次の一歩として、まず自分のプロジェクトで Lambda 関数の数とロールの共有状況を確認してみてください。関数ごとに roleArn を洗い出し、アタッチされているポリシーの許可サービスとコードが実際に呼び出しているAWSサービスを突き合わせる作業を、一度手動でも試してみる価値があります。

関数数が増えてこの作業が手に負えなくなってきたと感じたタイミングが、静的解析ツールの導入を検討する目安になります。

参考

Your Lambda Passes Tests Then Throws AccessDeniedException in Production

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。