securing-aws-lambda-execution-roles について
AWS サーバーレスチーム向けに、Lambda 実行ロールの権限を監査し、絞り込むセキュリティガイドです。CloudTrail の実際の API 使用状況を基に、最小権限ポリシー、権限境界、組織レベルの制限を扱います。
主な機能
- 01Lambda 実行ロール権限の監査
- 02CloudTrail の使用状況に基づく権限特定
- 03リソースを限定した最小権限ポリシー
- 04権限境界の設定
- 05Access Analyzer によるポリシー検証
- 06SCP によるロール標準の適用
活用シーン
- 01監査で見つかった過剰権限ロールの修正
- 02新しい Lambda 関数の権限定義
- 03チーム向け再利用可能な IAM テンプレート作成
- 04共有 AdministratorAccess ロールのリスク低減
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill securing-aws-lambda-execution-rolesインストール後、Claude Code で/securing-aws-lambda-execution-rolesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdscripts/agent.py詳細
AWS Lambda 実行ロールのセキュリティ保護
使用する場面
- 新しい Lambda 関数をデプロイし、IAM 実行ロールを定義するとき
- セキュリティ監査で発見された、過剰に許可された Lambda ロールを修正するとき
- サーバーレスアーキテクチャに最小権限のアクセスパターンを実装するとき
- チーム間で Lambda 関数に再利用できる IAM テンプレートを作成するとき
- Security Hub または Prowler が、過剰な権限を持つ Lambda 関数を報告したとき
使用しないでください。Lambda 関数の呼び出しを保護する場合(リソースベースのポリシーと API Gateway オーソライザーを使用してください)、Lambda コードのセキュリティを保護する場合(SAST ツールを使用してください)、または Lambda のネットワークセキュリティを保護する場合(VPC の設定とセキュリティグループを使用してください)。
前提条件
- ポリシーの作成、ロールの変更、Access Analyzer の操作に必要な IAM 権限
- アカウントで AWS IAM Access Analyzer が有効になっていること
- 実際の API 使用状況を収集するため、Lambda の CloudTrail データイベントが有効になっていること
- 権限を監査し、範囲を限定する対象の既存 Lambda 関数
- 各関数が必要とする AWS サービスとの連携についての理解
ワークフロー
ステップ 1:現在の Lambda 実行ロールの権限を監査する
すべての Lambda 関数と、それに関連付けられた IAM ロールを列挙し、過剰な権限を持つ関数を特定します。
# List all Lambda functions with their execution roles
aws lambda list-functions \
--query 'Functions[*].[FunctionName,Role]' --output table
# For each function, analyze attached policies
for func in $(aws lambda list-functions --query 'Functions[*].FunctionName' --output text); do
role_arn=$(aws lambda get-function-configuration --function-name "$func" --query 'Role' --output text)
role_name=$(echo "$role_arn" | awk -F'/' '{print $NF}')
echo "=== $func -> $role_name ==="
# Check for AWS managed policies (often too broad)
aws iam list-attached-role-policies --role-name "$role_name" \
--query 'AttachedPolicies[*].[PolicyName,PolicyArn]' --output table
# Check inline policies
for policy in $(aws iam list-role-policies --role-name "$role_name" --query 'PolicyNames' --output text); do
echo " Inline: $policy"
aws iam get-role-policy --role-name "$role_name" --policy-name "$policy" \
--query 'PolicyDocument' --output json
done
done
ステップ 2:CloudTrail で実際の API 使用状況を分析する
CloudTrail と IAM Access Analyzer を使用して、関数が実際に使用する API アクションを特定します。
# Query CloudTrail for actual API calls made by a Lambda execution role
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=Username,AttributeValue=LAMBDA_ROLE_NAME \
--start-time 2026-01-23T00:00:00Z \
--end-time 2026-02-23T00:00:00Z \
--query 'Events[*].[EventTime,EventName,EventSource]' \
--output table | sort -k2 | uniq -f1
# Use IAM Access Analyzer policy generation (based on CloudTrail activity)
aws accessanalyzer start-policy-generation \
--policy-generation-details '{
"principalArn": "arn:aws:iam::ACCOUNT:role/lambda-execution-role",
"cloudTrailDetails": {
"trailArn": "arn:aws:cloudtrail:us-east-1:ACCOUNT:trail/management-trail",
"startTime": "2026-01-23T00:00:00Z",
"endTime": "2026-02-23T00:00:00Z"
}
}'
# Check the generated policy
aws accessanalyzer get-generated-policy \
--job-id JOB_ID \
--query 'generatedPolicyResult.generatedPolicies[*].policy'
ステップ 3:最小権限の実行ポリシーを作成する
各関数に必要な特定のアクションとリソースのみを許可する、範囲を限定した IAM ポリシーを作成します。
# Example: Scoped policy for a function that reads from S3 and writes to DynamoDB
cat > lambda-scoped-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadInputBucket",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::input-data-bucket",
"arn:aws:s3:::input-data-bucket/*"
]
},
{
"Sid": "WriteDynamoDB",
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:BatchWriteItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:ACCOUNT:table/results-table"
},
{
"Sid": "CloudWatchLogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:ACCOUNT:log-group:/aws/lambda/my-function:*"
}
]
}
EOF
# Create the policy
aws iam create-policy \
--policy-name lambda-my-function-policy \
--policy-document file://lambda-scoped-policy.json
# Create execution role with scoped trust policy
cat > lambda-trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "ACCOUNT_ID"
}
}
}]
}
EOF
aws iam create-role \
--role-name lambda-my-function-role \
--assume-role-policy-document file://lambda-trust-policy.json
aws iam attach-role-policy \
--role-name lambda-my-function-role \
--policy-arn arn:aws:iam::ACCOUNT:policy/lambda-my-function-policy
ステップ 4:権限境界を適用する
権限境界を実装して、Lambda 実行ロールに付与できる権限の上限を設定します。
# Create a permission boundary that caps Lambda role capabilities
cat > lambda-permission-boundary.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowedServices",
"Effect": "Allow",
"Action": [
"s3:GetObject", "s3:PutObject", "s3:ListBucket",
"dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:UpdateItem",
"sqs:SendMessage", "sqs:ReceiveMessage", "sqs:DeleteMessage",
"sns:Publish",
"secretsmanager:GetSecretValue",
"kms:Decrypt", "kms:GenerateDataKey",
"logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents",
"xray:PutTraceSegments", "xray:PutTelemetryRecords"
],
"Resource": "*"
},
{
"Sid": "DenyPrivilegeEscalation",
"Effect": "Deny",
"Action": [
"iam:CreateUser", "iam:CreateRole", "iam:CreatePolicy",
"iam:AttachRolePolicy", "iam:AttachUserPolicy",
"iam:PutRolePolicy", "iam:PutUserPolicy",
"iam:CreateAccessKey", "iam:PassRole",
"lambda:CreateFunction", "lambda:UpdateFunctionConfiguration",
"sts:AssumeRole"
],
"Resource": "*"
}
]
}
EOF
# Create and apply the boundary
aws iam create-policy \
--policy-name lambda-permission-boundary \
--policy-document file://lambda-permission-boundary.json
aws iam put-role-permissions-boundary \
--role-name lambda-my-function-role \
--permissions-boundary arn:aws:iam::ACCOUNT:policy/lambda-permission-boundary
ステップ 5:IAM Access Analyzer でポリシーを検証する
Access Analyzer を使用して、セキュリティのベストプラクティスに照らしてポリシーを検証します。
# Validate the scoped policy
aws accessanalyzer validate-policy \
--policy-document file://lambda-scoped-policy.json \
--policy-type IDENTITY_POLICY \
--query 'findings[*].[findingType,issueCode,learnMoreLink]' --output table
# Check for unused access
aws accessanalyzer check-no-new-access \
--new-policy-document file://lambda-scoped-policy.json \
--existing-policy-document file://old-broad-policy.json \
--policy-type IDENTITY_POLICY
# Verify the permission boundary effectiveness
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::ACCOUNT:role/lambda-my-function-role \
--action-names iam:CreateUser iam:PassRole s3:GetObject dynamodb:PutItem \
--query 'EvaluationResults[*].[EvalActionName,EvalDecision]' --output table
ステップ 6:SCP でロールの標準を適用する
サービスコントロールポリシーを適用し、Lambda 関数が過度に広範なロールを使用できないようにします。
# SCP to deny Lambda functions using AdministratorAccess
cat > scp-deny-lambda-admin.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyLambdaAdminRole",
"Effect": "Deny",
"Action": "lambda:CreateFunction",
"Resource": "*",
"Condition": {
"ForAnyValue:StringLike": {
"lambda:FunctionArn": "*"
},
"ArnLike": {
"iam:PassedToService": "lambda.amazonaws.com"
}
}
},
{
"Sid": "RequirePermissionBoundary",
"Effect": "Deny",
"Action": [
"iam:CreateRole",
"iam:AttachRolePolicy",
"iam:PutRolePolicy"
],
"Resource": "arn:aws:iam::*:role/lambda-*",
"Condition": {
"StringNotEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::*:policy/lambda-permission-boundary"
}
}
}]
}
EOF
aws organizations create-policy \
--name "lambda-role-guardrails" \
--type SERVICE_CONTROL_POLICY \
--content file://scp-deny-lambda-admin.json
主な概念
| 用語 | 定義 |
|---|---|
| 実行ロール | 関数の実行中に Lambda が引き受ける IAM ロールです。関数が実行できるすべての AWS API アクションを定義します |
| 最小権限 | 関数が意図された操作を実行するために必要な最小限の権限のみを付与するセキュリティ原則です |
| 権限境界 | アイデンティティポリシーでより広範なアクセスが許可されている場合でも、実行ロールが持てる権限の上限を設定する IAM ポリシーです |
| IAM Access Analyzer | 実際の CloudTrail 使用状況に基づいて最小権限のポリシーを生成し、セキュリティ上の問題がないかポリシーを検証する AWS サービスです |
| リソース範囲限定ポリシー | ワイルドカードではなく正確なリソース ARN を指定し、必要な特定のリソースのみにアクセスを制限する IAM ポリシーです |
| Confused Deputy の防止 | 信頼ポリシーに aws:SourceAccount または aws:SourceArn 条件を追加し、クロスアカウントのロール引き受け攻撃を防止することです |
ツールとシステム
- IAM Access Analyzer:CloudTrail データから最小権限のポリシーを生成し、ポリシーのセキュリティを検証します
- IAM Policy Simulator:デプロイ前に、特定の API アクションに対するロールの有効な権限をテストします
- CloudTrail:実際の関数の権限使用状況を特定するために使用する、すべての API 呼び出しの監査ログです
- Prowler:ロールの権限と設定に関する Lambda 固有のチェック機能を備えたセキュリティツールです
- Checkov:CloudFormation/Terraform の Lambda IAM ポリシーを検証する、Infrastructure as Code スキャナーです
一般的なシナリオ
シナリオ:Lambda 関数の権限を AdministratorAccess から最小権限に絞り込む
コンテキスト:セキュリティ監査で、12 個の Lambda 関数が AdministratorAccess を持つ共有実行ロールを使用していることが判明しました。チームは、本番環境に影響を与えずに、各関数の権限を必要最小限に絞り込む必要があります。
アプローチ:
- Lambda の CloudTrail データイベントを有効にして、関数ごとの実際の API 使用状況を記録します
- 代表的な API 呼び出しのサンプルを収集するため、30 日間待ちます
- 各関数のロール使用状況に対して、IAM Access Analyzer のポリシー生成機能を使用します
- 実際の API 使用状況に基づき、関数ごとに個別の範囲を絞ったポリシーを作成します
- 権限境界を適用して、最大権限を制限します
- 範囲を絞ったロールをステージング環境にデプロイし、統合テストを実行します
- カナリアデプロイとロールバック計画を用いて、本番環境に展開します
- 古い広範なロールを削除する前に、IAM Policy Simulator で検証します
注意点:一部の Lambda 関数には、月に一度しか実行されないまれなコードパス(バッチジョブやエラーハンドラーなど)が存在する場合があります。30 日間の観測期間では、まれな API 呼び出しを見逃す可能性があります。CloudTrail のデータと併せて関数のコードを確認し、発生し得るすべての API 呼び出しを特定してください。生成されたポリシーだけに頼らず、Access Analyzer のポリシー検証機能を使用してください。
出力形式
Lambda Execution Role Security Report
========================================
Account: 123456789012
Review Date: 2026-02-23
Functions Audited: 34
ROLE PERMISSION SUMMARY:
Functions with AdministratorAccess: 3 (CRITICAL)
Functions with PowerUserAccess: 5 (HIGH)
Functions with wildcard actions: 12 (MEDIUM)
Functions with scoped policies: 14 (OK)
REMEDIATION PROGRESS:
[x] payment-processor: Scoped to DynamoDB + S3 + KMS (3 actions)
[x] order-notification: Scoped to SNS + SES (2 actions)
[ ] data-pipeline: Generating policy from 30-day CloudTrail data
[ ] image-resizer: Awaiting staging validation
PERMISSION BOUNDARY STATUS:
Functions with boundary applied: 14 / 34
Functions without boundary: 20 / 34
POLICY VALIDATION RESULTS:
Policies with security warnings: 4
Policies with errors: 0
Policies with suggestions: 12