

# 限制对 AWS Lambda Web 函数源的访问
<a name="private-content-restricting-access-to-lambda-web"></a>

您可以使用来源访问控制（OAC）限制对 AWS Lambda Web 函数源的访问。Lambda Web 函数提供自己的区域性或全球性 HTTPS 端点，您可以将其用作 CloudFront 分配的源域。有关 Lambda Web 函数的更多信息，请参阅《AWS Lambda 开发人员指南》**中的 [AWS Lambda Web 函数](https://docs.aws.amazon.com/lambda/latest/dg/web-functions.html)。

**注意**  
包含选择加入区域的全球性端点不支持带有 Lambda Web 函数的 OAC。如果端点将请求路由到选择加入区域，则 CloudFront 无法对该区域的请求进行签名。之后，源将返回 HTTP 403（禁止）错误。与全球性端点关联的所有区域都必须是默认启用的区域。

有关将 OAC 与 Lambda 函数 URL 源结合使用的信息，请参阅[限制对 AWS Lambda 函数 URL 源的访问](private-content-restricting-access-to-lambda.md)。

## 先决条件
<a name="oac-prerequisites-lambda-web"></a>

在创建和设置 OAC 之前，您必须拥有将 Lambda Web 函数作为源的 CloudFront 分配。源域名是 Lambda Web 函数端点的主机名。CloudFront 会根据主机名识别[端点类型](https://docs.aws.amazon.com/lambda/latest/dg/web-functions-endpoints.html#web-functions-endpoint-types)：
+ 区域性端点（`HomeRegion` 和 `PerRegion` 端点类型）：主机名以 `.lambda-web.{{AWS-Region}}.on.aws` 结尾
+ 全球性端点（`MultiRegion` 端点类型）：主机名以 `.lambda-web.global.on.aws` 结尾

您的配置还必须满足以下要求：
+ **端点身份验证类型**：端点的身份验证类型必须为 `IamAuth`。使用 `IamAuth` 时，端点会使用 AWS Identity and Access Management（IAM）对请求进行身份验证和授权。对于来自 CloudFront 的请求，会根据 Lambda Web 函数的基于资源的策略进行授权。CloudFront 代表查看器对请求进行签名，并且端点会对签名进行验证。有关更多信息，请参阅《AWS Lambda 开发人员指南》**中的 [CloudFront 集成](https://docs.aws.amazon.com/lambda/latest/dg/web-functions-endpoint-access-control.html#web-functions-endpoint-access-control-cloudfront)。
+ **缓存策略**：如果您的 Lambda Web 函数使用查看器的 `Authorization` 标头，您必须将该标头添加到[缓存策略](controlling-the-cache-key.md)中。此要求适用于每个使用该源的缓存行为。对于 `GET` 和 `HEAD` 请求，除非 `Authorization` 标头在缓存策略中，否则 CloudFront 会在转发请求移除该标头。有关更多信息，请参阅 [HTTP 请求标头和 CloudFront 行为（自定义源和 Amazon S3 源）](RequestAndResponseBehaviorCustomOrigin.md#request-custom-headers-behavior)。
+ **源请求策略**：使用不包括查看器的 `Host` 标头的源请求策略。Lambda Web 函数端点要求 `Host` 标头包含源域名，而不是 CloudFront 分配的域名。如果 `Host` 标头包含分配的域名，则端点将返回 HTTP 404（未找到）错误。如果您使用托管式源请求策略，请使用 `AllViewerExceptHostHeader`，而不要使用 `AllViewer`。有关更多信息，请参阅 [AllViewerExceptHostHeader](using-managed-origin-request-policies.md#managed-origin-request-policy-all-viewer-except-host-header)。

**注意**  
在使用带 OAC 的 Lambda Web 函数源的缓存行为上，不支持 Lambda@Edge 源请求和源响应触发器。此限制适用于区域性和全球性端点，也适用于直接访问或通过源组访问的源。CloudFront 会拒绝同时包含两者的分配配置。

## 向 CloudFront 授予访问 Lambda Web 函数的权限
<a name="oac-permission-to-access-lambda-web"></a>

将基于资源的策略附加到 Lambda Web 函数，以允许 CloudFront 服务主体（`cloudfront.amazonaws.com`）调用端点。用于调用端点的 IAM 操作是 `lambda:InvokeWebFunctionEndpoint`。该策略将附加到 Lambda Web 函数，但每条语句可以将 `Resource` 的范围限于特定的端点 ARN。使用 `Condition` 元素，仅在请求代表包含源的 CloudFront 分配时，才允许 CloudFront 访问端点。

**Example 适用于 CloudFront OAC 的基于资源的策略**  

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowCloudFrontOACAccess",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "lambda:InvokeWebFunctionEndpoint",
            "Resource": "arn:aws:lambda:us-east-1:{{111122223333}}:web-function/{{my-function}}/endpoint/{{prod}}",
            "Condition": {
                "StringEquals": {
                    "aws:SourceArn": "arn:aws:cloudfront::{{111122223333}}:distribution/{{EDFDVBD6EXAMPLE}}"
                }
            }
        }
    ]
}
```

要附加基于资源的策略，请使用带*函数* ARN（而不是端点 ARN）的 **put-resource-policy** 命令：

```
aws lambda-web put-resource-policy \
  --resource-arn "arn:aws:lambda:us-east-1:{{111122223333}}:web-function/{{my-function}}" \
  --policy file://policy.json \
  --region us-east-1
```

您可以使用 **get-resource-policy** 和 **delete-resource-policy** 命令查看或移除策略。

**注意**  
对于跨多个区域的端点，Lambda 会将策略更改复制到为该端点提供服务的所有区域。新策略或更新后的策略需要短暂时间才能在每个区域生效。有关更多信息，请参阅《AWS Lambda 开发人员指南》**中的[复制和最终一致性](https://docs.aws.amazon.com/lambda/latest/dg/web-functions-permissions.html#web-functions-permissions-resource-policy-replication)。

## 创建源访问控制
<a name="create-oac-lambda-web"></a>

要创建源访问控制（OAC），可以使用 AWS 管理控制台、CloudFormation、AWS CLI 或 CloudFront API。

------
#### [ Console ]

**创建源访问控制**

1. 登录 AWS 管理控制台，并通过以下网址打开 CloudFront 控制台：[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)。

1. 在导航窗格中，选择 **Origin access**（源访问）。

1. 选择 **Create control setting**（创建控制设置）。

1. 在 **Create control setting**（创建控制设置）表单上，执行以下操作：

   1. 在 **Details**（详细信息）窗格中，输入源访问控制的 **Name**（名称）和（可选）**Description**（描述）。

   1. 从**源类型**下拉列表中选择 **Lambda**。此源类型同时用于 Lambda 函数 URL 和 Lambda Web 函数。

   1. 如果您的源是全球性端点（主机名以 `.lambda-web.global.on.aws` 结尾），请选择**使用 SigV4a 签名协议**选项。对于区域性端点（主机名以 `.lambda-web.{{AWS-Region}}.on.aws` 结尾），请清除此选项。

   1. 对于**签名行为**，选择**始终签名，保留查看器授权**。此选项显示在**签署请求（推荐）**下，默认处于选中状态。Lambda Web 函数源仅支持此签名行为。有关更多信息，请参阅 [签名行为](#oac-signing-behavior-lambda-web)。

1. 选择**创建**。

**向分配中的 Lambda Web 函数源添加源访问控制**

1. 通过以下网址打开 CloudFront 控制台：[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)。

1. 选择具有要向其中添加 OAC 的 Lambda Web 函数源的分配，然后选择**源**选项卡。

1. 选择要向其中添加 OAC 的 Lambda Web 函数源，然后选择**编辑**。

1. 在**源访问**部分，选择**源访问控制设置（推荐）**。

1. 从**源访问控制**下拉菜单中，选择要使用的 OAC。

1. 选择**保存更改**。

分配开始部署到所有 CloudFront 边缘站点。当边缘站点收到新配置时，它会对自己发送到 Lambda Web 函数源的所有请求进行签名。

------
#### [ CLI ]

使用 **create-origin-access-control** 命令。对于区域性端点（主机名以 `.lambda-web.{{AWS-Region}}.on.aws` 结尾），请使用 `sigv4` 签名协议：

```
aws cloudfront create-origin-access-control \
    --origin-access-control-config '{
        "Name": "my-lambda-web-oac",
        "Description": "OAC for Lambda Web Function origin",
        "SigningProtocol": "sigv4",
        "SigningBehavior": "always-amz-auth",
        "OriginAccessControlOriginType": "lambda"
    }'
```

对于全球性端点（主机名以 `.lambda-web.global.on.aws` 结尾），请使用 `sigv4a` 签名协议：

```
aws cloudfront create-origin-access-control \
    --origin-access-control-config '{
        "Name": "my-lambda-web-global-oac",
        "Description": "OAC for global Lambda Web Function origin",
        "SigningProtocol": "sigv4a",
        "SigningBehavior": "always-amz-auth",
        "OriginAccessControlOriginType": "lambda"
    }'
```

------
#### [ CloudFormation ]

在 `OriginAccessControlConfig` 中指定以下值：
+ `SigningProtocol`：`sigv4`（区域性端点）或 `sigv4a`（全球性端点）
+ `SigningBehavior`: `always-amz-auth`
+ `OriginAccessControlOriginType`: `lambda`

**Example CloudFormation 模板**  

```
Type: AWS::CloudFront::OriginAccessControl
Properties:
  OriginAccessControlConfig:
    Description: An optional description for the origin access control
    Name: my-lambda-web-oac
    OriginAccessControlOriginType: lambda
    SigningBehavior: always-amz-auth
    SigningProtocol: sigv4a
```

有关更多信息，请参阅 *AWS CloudFormation 用户指南* 中的 [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html)。

------

仅在分配完成部署后，OAC 才会对每个请求生效。对于跨多个区域的端点，您之前附加的基于资源的策略也必须复制到为该端点提供服务的每个区域。在这两项操作完成之前，某些请求可能会收到来自源的临时 HTTP 403 响应。在分配完成部署且策略完成复制后，这些错误会自动得到纠正。

## 签名行为
<a name="oac-signing-behavior-lambda-web"></a>

Lambda Web 函数源仅支持 `always-amz-auth` 签名行为（控制台中的**始终签名，保留查看器授权**）。CloudFront 会始终对它发送到 Lambda Web 函数的所有请求进行签名，但不会替换来自查看器请求的 `Authorization` 标头。相反，CloudFront 会在专用 CloudFront 标头中添加其签名，并按原样将查看器的 `Authorization` 标头传递给源。通过此行为，您的 Lambda Web 函数会收到查看器的原始 `Authorization` 标头（例如，用于执行自己的身份验证或授权）。CloudFront 仍会对它发送到源的每个请求进行签名。要转发查看器的 `Authorization` 标头，您必须将该标头添加到每个使用源的缓存行为的[缓存策略](controlling-the-cache-key.md)中。

Lambda Web 函数源不支持其他签名行为（`always`、`never` 和 `no-override`）。任何其他源类型（包括 Lambda 函数 URL 源）均不支持 `always-amz-auth` 签名行为。

对于 `PUT`、`POST` 和 `PATCH` 请求，CloudFront 使用未签名的有效载荷（`UNSIGNED-PAYLOAD`）对源请求进行签名。CloudFront 签名不会涵盖请求正文。签名仍涵盖请求方法、路径、查询字符串以及用于标识分配的标头。因此，端点可以在调用 Lambda Web 函数之前，验证每个请求是否由 CloudFront 代表您的分配发出。请求正文在传输过程中受 CloudFront 与端点之间的 HTTPS 连接的保护。您无需在向 CloudFront 发出的请求中包含 `x-amz-content-sha256` 标头。如果查看器发送了该标头，CloudFront 在对源请求进行签名时不会使用它。