0
Help us understand the problem. What are the problem?

リソースベースポリシーで Lambda function URLs のアクセスを制御する

はじめに

2022/4/6 から利用可能になった Lambda function URLs (関数 URL) はリクエストの認証タイプに AWS_IAM を選択できます。AWS_IAM では IAM エンティティのポリシーと AWS Lambda のリソースベースポリシーに基づいてリクエストが認証されます。

リソースベースポリシーによる制御パターンについていくつか検証してみました。

結論

できたこと

  • クロスアカウントの呼び出しを許可するポリシーステートメントの設定
  • PrincipalOrgID を指定した、組織内からの呼び出しを許可するポリシーステートメントの設定
    • コンソールからは設定できないため、AWS CLI/SDK での AddPermission API の実行が必要

できなかったこと

検証の前提

今回は Lambda function URLs の 認証タイプは AWS_IAM に設定して検証しています。認証タイプに AWS_IAM を設定した場合、デフォルトではリソースベースポリシーは設定されません。同じアカウント内で lambda:InvokeFunctionUrl 権限を持つ IAM ユーザーまたはロールのみが関数 URL を呼び出せます。

image.png

AWS_IAM 認証によるリクエストを試すには curl 7.75.0 以降で利用可能な --aws-sigv4 オプション がお手軽です。

$ curl -i https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/ \
  -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" \
  --aws-sigv4 "aws:amz:ap-northeast-1:lambda" \
  --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}"

HTTP/1.1 200 OK
Date: Fri, 15 Apr 2022 02:38:38 GMT
Content-Type: application/json
Content-Length: 20
Connection: keep-alive
x-amzn-RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
X-Amzn-Trace-Id: root=x-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx;sampled=0

"Hello from Lambda!"

参考: 認証タイプを NONE に設定した場合

以下のようなリソースベースポリシーが設定されます。このポリシーにより、関数 URL にパブリックにアクセスできる状態になります。

    {
      "StatementId": "FunctionURLAllowPublicAccess",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "lambda:InvokeFunctionUrl",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:Lambda_Function_URLs_Policy_Test",
      "Condition": {
        "StringEquals": {
          "lambda:FunctionUrlAuthType": "NONE"
        }
      }
    }

クロスアカウントでの呼び出しを許可する

コンソールの アクセス権限を追加 から関数 URL 用のポリシーステートメントを設定できます。Principal にクロスアカウントでの呼び出しを許可する IAM エンティティの ARN を入力します。許可するアクションは lambda:InvokeFunctionUrl 固定です。以下の例では アカウント ID 111111111111 に対して呼び出しを許可しています。

image.png

以下のようなポリシーが設定され、クロスアカウントでの呼び出しができます。

    {
      "Sid": "x-account",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111111111111:root"
      },
      "Action": "lambda:InvokeFunctionUrl",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:Lambda_Function_URLs_Policy_Test",
      "Condition": {
        "StringEquals": {
          "lambda:FunctionUrlAuthType": "AWS_IAM"
        }
      }
    }

この方式の場合、許可する IAM エンティティごとにポリシーを追加する必要があります。

組織内からの呼び出しを許可する

PrincipalOrgID を指定し、組織内の AWS アカウントの任意の IAM エンティティからの呼び出しを許可する例です。
以下の理由からコンソールからは設定できませんでした。

  • 関数 URL のステートメント作成 UI では PrincipalOrgID を指定できない
  • AWS アカウントのステートメント作成 UI では、アクションに lambda:InvokeFunctionUrl を選択できない

image.png

AWS CLI を使用して AddPermission API を叩いた場合は設定できました。

$ aws lambda add-permission \
  --function-name Lambda_Function_URLs_Policy_Test \
  --function-url-auth-type AWS_IAM \
  --statement-id PrincipalOrgIDExample \
  --principal "*" \
  --action lambda:InvokeFunctionUrl  
  --principal-org-id o-a1b2c3e4d5

以下のようなリソースベースポリシーがアタッチされます。

    {
      "Sid": "PrincipalOrgIDExample",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "lambda:InvokeFunctionUrl",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:Lambda_Function_URLs_Policy_Test",
      "Condition": {
        "StringEquals": {
          "lambda:FunctionUrlAuthType": "AWS_IAM",
          "aws:PrincipalOrgID": "o-a1b2c3e4d5"
        }
      }
    }

Condition 要素を指定した細やかな制御はできない

AWS Lambda のリソースベースポリシーは AddPermission API で設定しますが、前述したとおり指定可能な要素が限られています。そのため、例えば "Condition": {"IpAddress": {"aws:SourceIp": "xxx.xxx.xxx.xxx/24"}} のように IP アドレス制限などを追加することは現状できません。

仮に IP アドレス制限を実装したい場合は、関数 URL から渡ってくる Event データの中に含まれる sorceIp から独自に実装する必要があります。

{
  "version": "2.0",
  "routeKey": "$default",
  "rawPath": "/my/path",
  "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
  "cookies": [
    "cookie1",
    "cookie2"
  ],
  "headers": {
    "header1": "value1",
    "header2": "value1,value2"
  },
  "queryStringParameters": {
    "parameter1": "value1,value2",
    "parameter2": "value"
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "<urlid>",
    "authentication": null,
    "authorizer": {
        "iam": {
                "accessKey": "AKIA...",
                "accountId": "111122223333",
                "callerId": "AIDA...",
                "cognitoIdentity": null,
                "principalOrgId": null,
                "userArn": "arn:aws:iam::111122223333:user/example-user",
                "userId": "AIDA..."
        }
    },
    "domainName": "<url-id>.lambda-url.us-west-2.on.aws",
    "domainPrefix": "<url-id>",
    "http": {
      "method": "POST",
      "path": "/my/path",
      "protocol": "HTTP/1.1",
      "sourceIp": "123.123.123.123",
      "userAgent": "agent"
    },
    "requestId": "id",
    "routeKey": "$default",
    "stage": "$default",
    "time": "12/Mar/2020:19:03:58 +0000",
    "timeEpoch": 1583348638390
  },
  "body": "Hello from client!",
  "pathParameters": null,
  "isBase64Encoded": false,
  "stageVariables": null
}

こちらは @_kensh さんから Twiiter でコメントいただきました。ありがとうございます。

参考

以上です。
参考になれば幸いです。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?