AWS Lambdaのパーミッション管理とセキュリティベストプラクティス
Lambdaにおける権限管理の全体像を理解する
AWS Lambdaでサーバーレスアプリケーションを構築する際、多くのエンジニアが最初に直面する壁が権限管理の複雑さです。Lambda関数には「実行ロール」というIAMロールを割り当てる必要があり、これは関数コードが他のAWSリソースにアクセスするための権限セットとして機能します。一方で、Lambda関数そのものにも「リソースポリシー」(関数ポリシーとも呼ばれます)を設定でき、これはどの主体が関数を呼び出したり操作できるかを定義するものです。
この2つの権限管理メカニズムを正しく理解し、適切に使い分けることが、セキュアで管理しやすいサーバーレスアーキテクチャを実現する鍵となります。私自身、過去のプロジェクトで「なぜS3からLambdaが呼び出せないのか」「クロスアカウントでの関数共有はどう実現すればよいのか」といった問題に直面し、試行錯誤を重ねてきました。その経験から言えることは、Lambda権限管理の本質を理解することで、多くのトラブルシューティングが劇的に簡単になるということです。
2つの権限管理方式の基本的な違い
Lambda権限管理における最も重要な概念は、以下の2種類の権限が存在することです。
権限の種類 | 概要 |
---|---|
関数がAWSリソースにアクセスするための権限 | Lambda関数内のコードが他のサービス(APIコールやリソース操作)を行う際に必要 |
他のユーザーやサービスがLambda関数を利用するための権限 | 関数を呼び出したり管理操作したりするために、呼び出し元に必要な許可 |
前者は実行ロールにアタッチされたIAMポリシーで定義し、後者はIAMユーザー/ロールへのポリシー付与、または関数自体のリソースポリシーによって制御します。
この違いを明確に理解していないと、「DynamoDBへの書き込み権限を追加したのに、なぜ関数が動かないのか」といった混乱に陥りがちです。
実行環境と呼び出し権限の分離という設計思想
AWSがこのような2層構造の権限管理を採用している背景には、「実行環境の権限」と「呼び出し権限」を明確に分離するという設計思想があります。これは、従来のEC2インスタンス上でアプリケーションを動かす場合とは大きく異なる考え方です。EC2の場合、インスタンスプロファイルに付与された権限がそのまま実行権限となりますが、Lambdaでは関数を「誰が呼び出せるか」という観点が追加されています。
この分離により、例えば「開発環境のAPI Gatewayからは開発用Lambda関数のみ呼び出し可能」「本番S3バケットからのイベントは本番Lambda関数のみがトリガー可能」といった、きめ細かなアクセス制御が実現できます。
IAMポリシー(アイデンティティベースのポリシー)の詳細
Lambda実行ロールの基本構成
Lambda実行ロールは、関数コードが実行時に使用するIAMロールです。最低限必要な権限として、CloudWatch Logsへの出力権限があり、これはAWS提供の管理ポリシー「AWSLambdaBasicExecutionRole」として提供されています。
実際のプロジェクトでは、この基本ポリシーに加えて、関数が利用する各種サービスへのアクセス権限を追加していきます。例えば、DynamoDBテーブルを更新する関数なら「dynamodb:UpdateItem」を特定のテーブルに許可するといったポリシーを実行ロールに付与します。
以下の表は、典型的なLambda実行ロールに付与される権限パターンをまとめたものです。
表 Lambda実行ロールの典型的な権限パターン
ユースケース | 必要な主な権限 | 推奨される管理ポリシー | 注意点 |
---|---|---|---|
基本的なログ出力 | logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents | AWSLambdaBasicExecutionRole | 全Lambda関数で必須 |
DynamoDB操作 | dynamodb:GetItem, dynamodb:PutItem, dynamodb:Query等 | カスタムポリシー | テーブル単位でARN指定推奨 |
S3操作 | s3:GetObject, s3:PutObject | カスタムポリシー | バケット・プレフィックス単位で制限 |
SQS連携 | sqs:ReceiveMessage, sqs:DeleteMessage | AWSLambdaSQSQueueExecutionRole | DLQ設定時は追加権限必要 |
VPC内実行 | ec2:CreateNetworkInterface等 | AWSLambdaVPCAccessExecutionRole | ENI作成権限が必要 |
この表から分かるように、各ユースケースに応じて必要最小限の権限を設定することが重要です。特にDynamoDBやS3といったデータストアへのアクセスでは、リソースレベルでのアクセス制御を適切に行うことで、万が一の権限昇格攻撃のリスクを最小化できます。
実行ロールの信頼ポリシーという重要な要素
Lambda実行ロールには、もう一つ重要な設定があります。それが「信頼ポリシー」(Trust Policy)です。これはIAMロールのリソースベースポリシーの一種で、「lambda.amazonaws.com」サービスプリンシパルを信頼できるように設定されています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
この信頼ポリシーにより、AWS Lambdaサービスがそのロールを引き受け(AssumeRole)、関数コードを実行できるようになります。実は、この仕組みを理解していると、より高度な権限委譲パターンも実装可能になります。
同一アカウント内での関数呼び出し権限
同一アカウント内で、あるIAMユーザーや別のサービス(例:Amazon Aurora)がLambda関数を呼び出す場合、その主体に対して「lambda:InvokeFunction」などのアクションを許可するIAMポリシーを付与できます。
{
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:<リージョン>:<アカウントID>:function:example_function"
}
このようなIAMポリシーは「誰(プリンシパル)に何を許可するか」を定義しますが、ポリシー内ではプリンシパル(主体)を指定しないのが特徴です。そのポリシーを付与されたIAMエンティティ自体がプリンシパルとなるためです。
リソースベースポリシー(Lambda関数ポリシー)の仕組み
関数ポリシーが必要となる典型的なシナリオ
リソースベースのポリシー(Lambda関数ポリシー)は、リソースに直接アタッチする権限ポリシーです。Lambda関数の場合、主に以下のようなシナリオで必要となります。
- S3バケットやSNSトピックからのイベントトリガー設定
- API GatewayからのLambda関数呼び出し
- クロスアカウントでの関数共有
- EventBridgeルールからの関数実行
特に重要なのは、S3やSNSといったAWSサービスがLambdaを「プッシュ実行」する場合、必ず関数ポリシーで明示的に許可を与える必要があるという点です。
サービスプリンシパルへの権限付与とセキュリティ上の注意点
以下は、S3バケットから特定のLambda関数を呼び出せるようにする関数ポリシーの例です。
{
"Sid": "lambda-allow-s3-my-function",
"Effect": "Allow",
"Principal": { "Service": "s3.amazonaws.com" },
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-2:123456789012:function:my-function",
"Condition": {
"StringEquals": { "AWS:SourceAccount": "123456789012" },
"ArnLike": { "AWS:SourceArn": "arn:aws:s3:::my-bucket" }
}
}
サービスプリンシパル(この場合は「s3.amazonaws.com」)にLambda呼び出しを許可する際は、必ず条件(Condition)で具体的なリソースを限定することが重要です。AWSの公式ドキュメントでも、「サービスプリンシパルに対してSourceArn等で発信元を限定しないと、他のアカウントがそのサービスを使って関数を呼び出せる可能性がある」と注意喚起されています。
実際のプロジェクトで、この条件設定を忘れたために、意図しない外部からのアクセスを許してしまった事例を見たことがあります。セキュリティ監査で発見されましたが、もし悪用されていたら深刻なインシデントになっていたかもしれません。
クロスアカウントアクセスの実装パターン
クロスアカウントでLambda関数を共有する場合、リソースポリシーの設定は必須となります。例えば、アカウントAの関数をアカウントBから呼び出す場合、以下の2つの設定が必要です。
- アカウントAの関数にリソースポリシーを設定(アカウントBのプリンシパルを許可)
- アカウントBのIAMユーザー/ロールにInvokeFunction権限を付与
この「両側での許可」という要件は、最初は煩雑に感じるかもしれません。しかし、これによって「意図しないクロスアカウントアクセス」を防ぐという重要な役割を果たしています。
IAMポリシーとリソースベースポリシーの実践的な使い分け
使い分けの判断基準と決定木
実際の開発現場では、どちらのポリシータイプを使うべきか迷うケースが多々あります。私が実践している判断基準をまとめると以下のようになります。
表 ポリシータイプ選択の判断基準
比較項目 | IAMポリシー(アイデンティティベース) | リソースベースポリシー(関数ポリシー) |
---|---|---|
適用対象 | IAMユーザー、グループ、ロール等の主体にアタッチ | Lambda関数に直接アタッチ |
主な用途 | 実行ロールに他サービスアクセス権限を付与、開発者ユーザーにLambda管理権限を付与 | 特定サービスや別アカウントからのInvokeを許可 |
プリンシパル指定 | ポリシー内でプリンシパル指定なし | Principalを明示指定(AWSサービス、アカウントID等) |
管理方法 | IAMコンソールで集中管理 | LambdaコンソールまたはCLIで関数ごとに管理 |
クロスアカウント | 単独では不可 | 必須要素 |
この表を参考に、同一アカウント内で人間ユーザーやCloudWatch EventsなどがLambdaを呼び出す場合はIAMポリシーで許可する方法がシンプルです。逆に、S3やSNSなどサービスがLambdaを直接呼び出すプッシュ統合ではリソースポリシーで関数側に許可を与える必要があります。
プル型とプッシュ型イベントソースの違い
Lambda関数のイベントソースには「プル型」と「プッシュ型」の2種類があり、それぞれ必要な権限設定が異なります。
プル型イベントソース(DynamoDB Streams、Kinesis、SQS等)の場合、Lambdaサービス自体がイベントをポーリングして処理するため、関数ポリシーは不要です。代わりに実行ロールにそのサービスへの読み取り権限が必要になります。一方、プッシュ型イベントソース(S3、SNS、EventBridge等)では、関数ポリシーによる許可が必須です。
この違いを理解していないと、「DynamoDB StreamsはIAMロールだけで動くのに、なぜS3トリガーは関数ポリシーが必要なのか」という疑問に悩まされることになります。実際、私も最初はこの違いに気づかず、S3トリガーの設定で何時間も費やしてしまった経験があります。
スケーラビリティを考慮した設計アプローチ
環境が小規模であれば、関数ごとにリソースポリシーを設定するやり方でも十分シンプルです。しかし関数や連携相手が増えてくると、IAMロールを活用した方が一括管理しやすい場合があります。
例えば、100個以上のLambda関数を管理するような大規模プロジェクトでは、以下のような階層的な権限管理戦略を採用することをお勧めします。
- 環境別(dev/stg/prod)でIAMロールを分離
- 機能別にロールをグルーピング(API系、バッチ系、データ処理系等)
- 共通的な権限は管理ポリシーとして定義し、複数ロールで再利用
ただし、ポリシーサイズには上限(6,144文字)があるため、あまりに多くの権限を1つのポリシーに詰め込むことはできません。適切な粒度での分割が必要です。
Lambdaセキュリティのベストプラクティス
最小権限の原則を徹底する実装パターン
Lambda実行ロールや関連IAMポリシーには、関数が実際に必要とするアクション・リソースだけを許可することが基本です。AWSのベストプラクティスでも「最も制限的な権限を使う」ことが推奨されています。
実践的なアプローチとして、私は以下のステップで権限を設計しています。
- 開発初期は広めの権限で機能を実装
- CloudTrailログを分析し、実際に使用されているAPIを特定
- 必要最小限の権限に絞り込み
- 定期的なレビューで未使用権限を削除
特に重要なのは、「Resource: "*"」(全リソース許可)を避けることです。Lambda実行ロールに他サービスへの全権限を与えると、万一の関数暴走時に被害が拡大します。
継続的な監視と改善サイクルの構築
セキュリティは「設定して終わり」ではありません。継続的な監視と改善が不可欠です。
AWS CloudTrailを有効化し、Lambdaに関するすべてのAPIコール履歴を記録・モニタリングすることは基本中の基本です。特に「AddPermission」(関数ポリシー変更)や「UpdateFunctionConfiguration」「UpdateFunctionCode」(設定・コード変更)など重要な操作は管理イベントとして自動的にログに残ります。
さらに、以下のサービスを組み合わせることで、より強固なセキュリティ体制を構築できます。
- AWS Security Hub:Lambda関数のパブリックアクセスなどを自動検出
- IAM Access Analyzer:意図しない外部アクセスを検出
- Amazon GuardDuty:Lambda保護機能で悪意ある挙動を検知
インシデント発生時の対応準備
万が一のセキュリティインシデントに備えて、以下の準備をしておくことをお勧めします。
- 緊急時の権限剥奪手順の文書化
- Lambda関数の自動停止スクリプトの準備
- CloudTrailログの保全と分析手順の確立
- インシデント対応チームの連絡体制整備
実際のプロジェクトで、誤って過剰な権限を付与してしまったケースがありました。幸い、Security Hubのアラートですぐに気づき、影響が出る前に修正できましたが、監視体制がなければ深刻な事態になっていたかもしれません。
実装時によくあるトラブルと解決策
S3トリガーが動かない典型的なケース
「S3にファイルをアップロードしたのにLambdaが起動しない」という問題は、Lambda開発者なら誰もが一度は経験するトラブルです。多くの場合、以下のいずれかが原因です。
- 関数ポリシーでS3サービスプリンシパルへの許可が不足
- S3バケットのイベント通知設定の不備
- SourceAccount/SourceArnの条件設定ミス
トラブルシューティングの際は、まずCloudTrailでInvokeFunctionのAPIコールが記録されているか確認し、次に関数ポリシーの内容を検証するという手順が効率的です。
クロスアカウントアクセスでの権限不足エラー
クロスアカウントでLambda関数を呼び出す際、「AccessDeniedException」が発生するケースがよくあります。この場合、以下のチェックポイントを確認してください。
- 呼び出される側:関数ポリシーで相手アカウントのプリンシパルを許可しているか
- 呼び出す側:IAMユーザー/ロールにInvokeFunction権限があるか
- リージョンが正しく指定されているか(ARNのリージョン部分)
特に見落としがちなのは、関数のバージョンやエイリアスを使用している場合、それらも含めたARNで許可を設定する必要があるという点です。
VPC内Lambda関数の権限設定ミス
VPC内でLambda関数を実行する場合、「AWSLambdaVPCAccessExecutionRole」管理ポリシーの付与を忘れがちです。このポリシーがないと、ENI(Elastic Network Interface)の作成ができず、関数がタイムアウトしてしまいます。
また、セキュリティグループとネットワークACLの設定も権限と同様に重要です。Lambda関数からの外部通信が必要な場合は、適切なアウトバウンドルールの設定を忘れないようにしましょう。
まとめ
AWS Lambdaの権限管理は、一見複雑に見えますが、「実行権限」と「呼び出し権限」という2つの観点で整理すると、その構造がクリアになります。IAMポリシーとリソースベースポリシーはそれぞれ異なる役割を持ち、適切に使い分けることで、セキュアで管理しやすいサーバーレスアーキテクチャを実現できます。
最小権限の原則を守りつつ、CloudTrailやSecurity Hubなどの監視サービスを活用した継続的な改善サイクルを回すことが、長期的な運用成功の鍵となります。
権限管理は面倒に感じるかもしれませんが、最初にきちんと設計しておくことで、後々のトラブルシューティングや監査対応が格段に楽になります。
サーバーレスアーキテクチャの普及により、Lambda関数の利用はますます拡大していくでしょう。その中で、適切な権限管理スキルを身につけることは、エンジニアとしての市場価値を高めることにもつながります。本記事で紹介した考え方と実践的なアプローチが、皆様のLambda開発の一助となれば幸いです。