コンテンツにスキップ

CT.LAMBDA.PV.1

検証日: 2026-03-22 / リージョン: ap-northeast-1

コントロールの説明

Lambda 関数 URL の認証タイプを AWS_IAM に強制し、NONE(認証なし)での作成・更新を禁止します。

本コントロールは SCP により、lambda:CreateFunctionUrlConfig および lambda:UpdateFunctionUrlConfig API で AuthType: NONE を指定する操作をブロックします。AuthType: AWS_IAM での操作は許可されます。

関数 URL の認証タイプには AWS_IAMNONE の 2 種類があります。AWS_IAM はリクエストに IAM 認証(SigV4 署名)を要求します。AWS SDK や AWS CLI は自動で署名を付与するため、AWS 内のサービス間通信であれば追加の実装なく利用できます。一方、AWS 外からのアクセスでは呼び出し側で SigV4 署名の実装が必要になります。特に Webhook 受信のように送信側の仕様を変更できないケースでは AWS_IAM は利用できないため、関数 URL ではなく API Gateway の利用が推奨されます。NONE は Lambda サービス側で認証を行わず、アクセス制御をリソースベースポリシーに委ねます。NONE 単体では即座にパブリック公開にはなりませんが、AddPermissionPrincipal: * を追加するだけでパブリック公開になるため、不適切な設定の入口を塞ぐことが重要です。

なお、同じシリーズの CT.LAMBDA.PV.2AddPermission による Principal: * の設定をブロックするコントロールです。PV.2 だけでも関数 URL のパブリック公開は間接的に防げますが、PV.1 を併用することで AuthType: NONE の関数 URL 自体を作らせない多層防御が実現できます。

検証の流れ

    flowchart LR
    A[1. 事前準備] --> B[2. AuthType:NONE<br>で関数URL作成成功]
    B --> C[3. CT.LAMBDA.PV.1<br>有効化]
    C --> D[4. 既存の関数URL<br>維持を確認]
    C --> E[5. 新規 AuthType:NONE<br>作成拒否を確認]
    C --> F[6. AuthType:AWS_IAM<br>作成成功を確認]
    D & E & F --> G[7. CloudTrail<br>で確認]
    G --> H[8. CT.LAMBDA.PV.1<br>無効化]
    H --> I[9. AuthType:NONE<br>作成成功を確認]
  
本コントロール(関数 URL の AuthType)に直接対応する Security Hub CSPM コントロールは確認できませんでした。Lambda.1 は「リソースベースポリシーがパブリックアクセスを禁止しているか」をチェックするものであり、AuthType の設定は評価対象外です。

結果

  • コントロールの有効化前、Lambda 関数 URL を AuthType: NONE で作成できることを確認できた。
  • コントロールの有効化後、既存の関数 URL(AuthType: NONE)は維持されることを確認できた。SCP は API コールをブロックするだけで既存設定には遡及しない。
  • 有効化中に lambda:CreateFunctionUrlConfigAuthType: NONE)を試みると、explicit deny in a service control policy で拒否されることを確認できた。
  • 有効化中でも AuthType: AWS_IAM での関数 URL 作成は許可されることを確認できた。
  • 拒否されたイベントが CloudTrail に記録されること、および管理アカウントの Organization Trail(CloudWatch Logs)からも確認できることを確認できた。
  • コントロールの無効化後、再び AuthType: NONE での作成が可能になることを確認できた。

1. 事前準備

検証用の IAM 実行ロールと Lambda 関数を作成する。

aws iam create-role \
  --role-name ct-lambda-pv1-test-role \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {"Service": "lambda.amazonaws.com"},
      "Action": "sts:AssumeRole"
    }]
  }' \
  --query 'Role.Arn'
"arn:aws:iam::<Workload のアカウント ID>:role/ct-lambda-pv1-test-role"

Lambda 関数を 2 つ作成する(有効化前テスト用と有効化後テスト用)。

echo 'def handler(event, context): return "ok"' > lambda_function.py
zip function.zip lambda_function.py
aws lambda create-function \
  --function-name ct-lambda-pv1-test-1 \
  --runtime python3.12 \
  --role arn:aws:iam::<Workload のアカウント ID>:role/ct-lambda-pv1-test-role \
  --handler lambda_function.handler \
  --zip-file fileb://function.zip \
  --query '{FunctionName:FunctionName,FunctionArn:FunctionArn}'
{
    "FunctionName": "ct-lambda-pv1-test-1",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:<Workload のアカウント ID>:function:ct-lambda-pv1-test-1"
}
aws lambda create-function \
  --function-name ct-lambda-pv1-test-2 \
  --runtime python3.12 \
  --role arn:aws:iam::<Workload のアカウント ID>:role/ct-lambda-pv1-test-role \
  --handler lambda_function.handler \
  --zip-file fileb://function.zip \
  --query '{FunctionName:FunctionName,FunctionArn:FunctionArn}'
{
    "FunctionName": "ct-lambda-pv1-test-2",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:<Workload のアカウント ID>:function:ct-lambda-pv1-test-2"
}

2. コントロール有効化前の確認

関数 URL を AuthType: NONE で作成する。

aws lambda create-function-url-config \
  --function-name ct-lambda-pv1-test-1 \
  --auth-type NONE \
  --query '{FunctionUrl:FunctionUrl,AuthType:AuthType}'
{
    "FunctionUrl": "https://<関数 URL ID>.lambda-url.ap-northeast-1.on.aws/",
    "AuthType": "NONE"
}

3. 対象の予防コントロールを有効化(例外設定なし)

Control Tower の管理アカウントで、対象の OU にコントロールが有効になっていないことを確認する。

aws controltower list-enabled-controls \
  --target-identifier <OU の ARN> \
  --profile Master
{
    "enabledControls": []
}

コントロールを有効化する。

aws controltower enable-control \
  --control-identifier arn:aws:controlcatalog:::control/3qpnxfs5vtzd2v2ql2f2mu7tq \
  --target-identifier <OU の ARN> \
  --profile Master
{
    "arn": "arn:aws:controltower:ap-northeast-1:<管理アカウント ID>:enabledcontrol/<enabledcontrol ID>",
    "operationIdentifier": "<オペレーション ID>"
}

有効化が完了するまで待機する。

aws controltower get-control-operation \
  --operation-identifier <オペレーション ID> \
  --query 'controlOperation.{operationType:operationType,status:status,statusMessage:statusMessage}' \
  --profile Master
{
    "operationType": "ENABLE_CONTROL",
    "status": "SUCCEEDED",
    "statusMessage": "Operation was successful."
}
get-control-operationSUCCEEDED を返した後も、SCP の実際の適用には数分のラグがある場合があります。ステップ 5 で拒否されない場合は、数分待ってから再試行してください。

4. 既存設定は維持されることの確認

有効化前に作成した関数 URL(AuthType: NONE)が維持されていることを確認する。

aws lambda get-function-url-config \
  --function-name ct-lambda-pv1-test-1 \
  --query '{FunctionUrl:FunctionUrl,AuthType:AuthType}'
{
    "FunctionUrl": "https://<関数 URL ID>.lambda-url.ap-northeast-1.on.aws/",
    "AuthType": "NONE"
}

有効化前に作成した AuthType: NONE の関数 URL は、コントロール有効化後も維持される。

5. 新規操作は制限(拒否)されることの確認

別の関数で AuthType: NONE の関数 URL を作成する。

aws lambda create-function-url-config \
  --function-name ct-lambda-pv1-test-2 \
  --auth-type NONE
An error occurred (AccessDeniedException) when calling the CreateFunctionUrlConfig operation:
User: arn:aws:sts::<Workload のアカウント ID>:assumed-role/<ロール名>/<セッション名>
is not authorized to perform: lambda:CreateFunctionUrlConfig on resource:
arn:aws:lambda:ap-northeast-1:<Workload のアカウント ID>:function:ct-lambda-pv1-test-2
with an explicit deny in a service control policy:
arn:aws:organizations::<管理アカウント ID>:policy/<組織 ID>/service_control_policy/<ポリシー ID>

6. AuthType: AWS_IAM での作成は許可されることの確認

同じ関数で AuthType: AWS_IAM の関数 URL を作成する。SCP の Condition は lambda:FunctionUrlAuthTypeAWS_IAM でない場合にのみ Deny するため、AWS_IAM での作成は許可される。

aws lambda create-function-url-config \
  --function-name ct-lambda-pv1-test-2 \
  --auth-type AWS_IAM \
  --query '{FunctionUrl:FunctionUrl,AuthType:AuthType}'
{
    "FunctionUrl": "https://<関数 URL ID>.lambda-url.ap-northeast-1.on.aws/",
    "AuthType": "AWS_IAM"
}

7. CloudTrail での確認

拒否されたイベントが CloudTrail に記録されていることを確認する。

Workload アカウントの CloudTrail イベント履歴から確認する。

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=CreateFunctionUrlConfig \
  --start-time <検索開始時刻> \
  --end-time <検索終了時刻> \
  --query 'Events[].CloudTrailEvent' \
  --output text | jq 'select(.errorCode != null) | {eventName, errorCode, errorMessage}'
{
  "eventName": "CreateFunctionUrlConfig",
  "errorCode": "AccessDenied",
  "errorMessage": "User: arn:aws:sts::<Workload のアカウント ID>:assumed-role/<ロール名>/<セッション名> is not authorized to perform: lambda:CreateFunctionUrlConfig on resource: arn:aws:lambda:ap-northeast-1:<Workload のアカウント ID>:function:ct-lambda-pv1-test-2 with an explicit deny in a service control policy: arn:aws:organizations::<管理アカウント ID>:policy/<組織 ID>/service_control_policy/<ポリシー ID>"
}

errorMessageexplicit deny in a service control policy と記録されており、SCP による拒否であることがわかる。

管理アカウントの Organization Trail(CloudWatch Logs)からも同じイベントを確認できる。

aws logs start-query \
  --log-group-name "aws-controltower/CloudTrailLogs" \
  --start-time $(date -d '<検索開始時刻>' +%s) \
  --end-time $(date -d '<検索終了時刻>' +%s) \
  --query-string 'fields @timestamp, eventName, errorCode, errorMessage
    | filter eventName like /CreateFunctionUrlConfig/ and errorCode like /AccessDenied/
    | sort @timestamp asc' \
  --profile Master

queryId が返るので、これを使って結果を取得する。

{
    "queryId": "<クエリ ID>"
}
aws logs get-query-results \
  --query-id <クエリ ID> \
  --query '{results:results,status:status}' \
  --profile Master
{
    "results": [
        [
            {"field": "@timestamp", "value": "<タイムスタンプ>"},
            {"field": "eventName", "value": "CreateFunctionUrlConfig"},
            {"field": "errorCode", "value": "AccessDenied"},
            {"field": "errorMessage", "value": "User: arn:aws:sts::<Workload のアカウント ID>:assumed-role/<ロール名>/<セッション名> is not authorized to perform: lambda:CreateFunctionUrlConfig on resource: arn:aws:lambda:ap-northeast-1:<Workload のアカウント ID>:function:ct-lambda-pv1-test-2 with an explicit deny in a service control policy: arn:aws:organizations::<管理アカウント ID>:policy/<組織 ID>/service_control_policy/<ポリシー ID>"},
            {"field": "@ptr", "value": "<ログポインタ>"}
        ]
    ],
    "status": "Complete"
}

管理アカウントの CloudWatch Logs にも同じ拒否イベントが記録されていることを確認できた。

8. 対象の予防コントロールを無効化

検証完了後、コントロールを無効化する。

aws controltower disable-control \
  --control-identifier arn:aws:controlcatalog:::control/3qpnxfs5vtzd2v2ql2f2mu7tq \
  --target-identifier <OU の ARN> \
  --profile Master
{
    "operationIdentifier": "<オペレーション ID>"
}
aws controltower get-control-operation \
  --operation-identifier <オペレーション ID> \
  --query 'controlOperation.{operationType:operationType,status:status,statusMessage:statusMessage}' \
  --profile Master
{
    "operationType": "DISABLE_CONTROL",
    "status": "SUCCEEDED",
    "statusMessage": "Operation was successful."
}

9. 制限解除の確認

コントロール無効化後、再び AuthType: NONE での関数 URL 作成が可能になることを確認する。

ステップ 2 で作成した関数 URL を削除してから再作成する。

aws lambda delete-function-url-config --function-name ct-lambda-pv1-test-1
(出力なし)
aws lambda create-function-url-config \
  --function-name ct-lambda-pv1-test-1 \
  --auth-type NONE \
  --query '{FunctionUrl:FunctionUrl,AuthType:AuthType}'
{
    "FunctionUrl": "https://<関数 URL ID>.lambda-url.ap-northeast-1.on.aws/",
    "AuthType": "NONE"
}

10. クリーンアップ

検証で作成したリソースをすべて削除する。

# 関数URLを削除
aws lambda delete-function-url-config --function-name ct-lambda-pv1-test-1
aws lambda delete-function-url-config --function-name ct-lambda-pv1-test-2
(出力なし)
# Lambda関数を削除
aws lambda delete-function --function-name ct-lambda-pv1-test-1
aws lambda delete-function --function-name ct-lambda-pv1-test-2
(出力なし)
# IAMロールを削除
aws iam delete-role --role-name ct-lambda-pv1-test-role
(出力なし)

Amazonアソシエイトリンク