CT.LAMBDA.PV.1
コントロールの説明
Lambda 関数 URL の認証タイプを AWS_IAM に強制し、NONE(認証なし)での作成・更新を禁止します。
本コントロールは SCP により、lambda:CreateFunctionUrlConfig および lambda:UpdateFunctionUrlConfig API で AuthType: NONE を指定する操作をブロックします。AuthType: AWS_IAM での操作は許可されます。
関数 URL の認証タイプには AWS_IAM と NONE の 2 種類があります。AWS_IAM はリクエストに IAM 認証(SigV4 署名)を要求します。AWS SDK や AWS CLI は自動で署名を付与するため、AWS 内のサービス間通信であれば追加の実装なく利用できます。一方、AWS 外からのアクセスでは呼び出し側で SigV4 署名の実装が必要になります。特に Webhook 受信のように送信側の仕様を変更できないケースでは AWS_IAM は利用できないため、関数 URL ではなく API Gateway の利用が推奨されます。NONE は Lambda サービス側で認証を行わず、アクセス制御をリソースベースポリシーに委ねます。NONE 単体では即座にパブリック公開にはなりませんが、AddPermission で Principal: * を追加するだけでパブリック公開になるため、不適切な設定の入口を塞ぐことが重要です。
なお、同じシリーズの CT.LAMBDA.PV.2 は AddPermission による 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>作成成功を確認]
結果
- コントロールの有効化前、Lambda 関数 URL を
AuthType: NONEで作成できることを確認できた。 - コントロールの有効化後、既存の関数 URL(
AuthType: NONE)は維持されることを確認できた。SCP は API コールをブロックするだけで既存設定には遡及しない。 - 有効化中に
lambda:CreateFunctionUrlConfig(AuthType: 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.pyaws 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-operation が SUCCEEDED を返した後も、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 NONEAn 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:FunctionUrlAuthType が AWS_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>"
}errorMessage に explicit 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 MasterqueryId が返るので、これを使って結果を取得する。
{
"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
(出力なし)