Lambda関数のリソースベースポリシー SorceArn にワイルドカードを含めて指定して ValidationError が表示されたときに確認したこと

2021.12.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ALB(Application Load Balancer)のターゲットに指定するLambdaのリソースベースポリシーについて考えていました。

SorceArnで指定した許可する呼び出し元のリソースを Condition ブロック内の ArnLike で評価します。仮にSorceArnにワイルドカードを含めるとどのように評価されるのか検証していました。バリデーションエラーが出力される原因を特定できなかったのですが、同じエラーの調査に時間を溶かす方がいるかもしれませんのでわかった範囲の情報を共有します。

マネージメントコンソール上のエラーメッセージ

[ARN] is not a valid target group ARN (Service: [ServiceName]; Status Code: 400; Error Code: ValidationError; Request ID: 0000; Proxy: null)

切り分けまとめ

ALBにリクエストを送るとALBからバックエンドのLambdaを呼び出す環境で検証しました。

  • リソースベースポリシーのSourceArnにワイルドカードを使うことができる
    • マネージメントコンソールと、AWS CLIからも設定できることを確認
  • SourceArnにワイルドカードを含むARNを設定するとバリデーションエラーになる
    • この状態でもリソースベースポリシーは機能しているようでLambdaを呼び出すことができている

リソースベースポリシーとは

Lambda関数にはリソースベースポリシーというアクセス権限設定があります。たとえばAPI Gatewayや、EventBridgeなどのリソースからLambda関数を呼び出すときには、リソースベースポリシーで呼び出し元のリソース名(ARN)を許可しておく必要があります。

リソースベースポリシーの詳細については以下のリンクを参照ください。

以下のリソースベースポリシーはSourceArnでターゲットグループのARNを許可した例です。ここにワイルドカードを入れてるとどうなるかを検証していました。

リソースベースポリシーの例

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "test-lambda-LambdaPermission-M0R26XNT3BUT",
      "Effect": "Allow",
      "Principal": {
        "Service": "elasticloadbalancing.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:target-lambda",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/target-lambda-tg/e5934698927d10c5"
        }
      }
    }
  ]
}

リソースベースポリシーでの許可

リソースベースポリシーでSourceArnに呼び出し元のARN(Amazon Resorce Name)を明示的に指定し、最小限の範囲で許可する方法が一般的です。マネージメントコンソールからLambda関数を作成する場合はあまり意識しませんが、CloudFormationや、SAMを利用して作成する場合は自前でポリシーを作成し、Lambda関数に関連付けする必要があります。

SourceArnは Condition ブロック内でArnLikeによって評価されます。仕様についておさらいしましょう。

ArnLikeの仕様

ワイルドカードは使えることを確認できました。

Case-sensitive matching of the ARN. Each of the six colon-delimited components of the ARN is checked separately and each can include a multi-character match wildcard (*) or a single-character match wildcard (?). The ArnEquals and ArnLike condition operators behave identically.

DeepL翻訳

ARNの大文字・小文字を区別したマッチング。ARNの6つのコロンで区切られたコンポーネントはそれぞれ個別にチェックされ、それぞれに複数文字のマッチワイルドカード(*)または1文字のマッチワイルドカード(?)を含めることができます。ArnEqualsとArnLikeの条件演算子の動作は同じです。

試してみる

一般的なARNの指定方法、ワイルドカードを含めた指定方法を数パターンを試してみました。

フルパスのARN指定

マネージメントコンソールからの設定は限定的で決まった項目に入力するだけです。 フルパスという表現が適切かはわからないのですがリソース名を一意に示せるARNを指定します。

設定内容は以下の様に登録されます。ソースARNに入力した内容は Conditionブロック内のArnLikeで評価されています。

リソースベースポリシー

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "test-lambda-LambdaPermission-M0R26XNT3BUT",
      "Effect": "Allow",
      "Principal": {
        "Service": "elasticloadbalancing.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:target-lambda",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/target-lambda-tg/e5934698927d10c5"
        }
      }
    }
  ]
}

ALBのターゲットに登録してあるLambdaです。所定のパスにGETリクエストを送るとLambdaが実行されます。期待通りのレスポンスが返ってることを確認できました。

$ curl http://labmdaalb-dev-elb-818537013.ap-northeast-1.elb.amazonaws.com/v1/test1
{"message": "I am Lambda-1 behind ALB. "}⏎

ワイルドカードで指定

ターゲットグループARN末尾の英数ランダムの箇所をワイルドカードに置き換えてみます。

# 変更前
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/target-lambda-tg/e5934698927d10c5

# 変更後
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/target-lambda-tg/*

保存後、マネージメントコンソール上部に以下のエラーメッセージが表示されます。

[ARN] is not a valid target group ARN (Service: [ServiceName]; Status Code: 400; Error Code: ValidationError; Request ID: 0000; Proxy: null)

日本語表示だと文字化けします。バリデーションエラーでターゲットグループのARNが有効ではないという肝心な部分は読み取れるのでなんとか大丈夫です。

英語表示に切り替えると問題ありません。

変更箇所はSourceArnにワイルドカード含めただけです。ワイルドカード周辺に原因があると考えられます。何パターンから試してみた結果をまとめした。しかし、どこが原因なのかわかりませんでした。

NGパターン集

# バリデーションエラー出力パターン(NG)
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/target-lambda-tg/*
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/target-lambda-tg*
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/*

OKパターン集

# バリデーションエラー未出力パターン(OK)
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup*
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:*

バリデーションエラーがでている状態のポリシーでもLambdaを呼び出しレスポンスが返ってきます。ワイルドカードを正しく解釈しターゲットグループを許可しているように思えます。

$ curl http://labmdaalb-dev-elb-818537013.ap-northeast-1.elb.amazonaws.com/v1/test1
{"message": "I am Lambda-1 behind ALB. "}⏎

リソースベースポリシーの全文は以下の内容です。

リソースベースポリシー

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "test-lambda-LambdaPermission-M0R26XNT3BUT",
      "Effect": "Allow",
      "Principal": {
        "Service": "elasticloadbalancing.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:target-lambda",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/*"
        }
      }
    }
  ]
}

リソースベースポリシーを未設定のとき

リソースベースポリシーを削除しました。

明示的な許可がないためALBからのLambdaの呼び出しに失敗し、Lambdaから期待したレスポンスが返ってきません。リソースベースポリシーは正常に機能していることが確認できました。

$ curl http://labmdaalb-dev-elb-818537013.ap-northeast-1.elb.amazonaws.com/v1/test1
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
</body>
</html>

AWS CLIからリソースベースポリシーを登録したとき

AWS CLIからリソースベースポリシーを登録してみます。

aws lambda add-permission \
    --function-name target-lambda \
    --action lambda:InvokeFunction \
    --statement-id  elb1\
    --principal elasticloadbalancing.amazonaws.com \
	--source-arn "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/*"

正常に処理できたようです。

実行結果

{
    "Statement": "{\"Sid\":\"elb1\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"elasticloadbalancing.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:ap-northeast-1:123456789012:function:target-lambda\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/*\"}}}"
}

意図した通りのリソースベースポリシーがAWS CLIから登録できています。ポリシー内容に関してはマネージメントコンソールからとの登録と同じであることが確認できました。

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "elb1",
      "Effect": "Allow",
      "Principal": {
        "Service": "elasticloadbalancing.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:target-lambda",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/*"
        }
      }
    }
  ]
}

マネージメントコンソールから確認すると同じバリデーションエラーのメッセージが表示されています。

しかし、マネージメントコンソールで登録したときと同様にLambdaからのレスポンスは返ってきます。

$ curl http://labmdaalb-dev-elb-818537013.ap-northeast-1.elb.amazonaws.com/v1/test1
{"message": "I am Lambda-1 behind ALB. "}⏎

確認できたこと

切り分けしたことをまとめます。

  • リソースベースポリシーのSourceArnにワイルドカードを使うことができる
    • マネージメントコンソールと、AWS CLIからも設定できることを確認
  • SourceArnにワイルドカードを含むARNを設定するとバリデーションエラーになる
    • この状態でもリソースベースポリシーは機能しているようでLambdaを呼び出すことができている

こうなってくるとリソースベースポリシーではフルパスの一意なARNを指定して権限を緩めない設定が無難に思えます。通常はワイルドカード入れることないと思いますし、最小権限にするには通常通りの設定の方が好ましいです。バリデーションエラーについてなにかわかれば追記する予定です。

おわりに

リソースベースポリシーについて理解を深めようとしたら想定と異なる悩みが生まれました。日本語表示時の文字化けについてはフィードバックはしました。