我使用 S3 REST API 终端节点作为我的 CloudFront 分配源。为什么我会收到“403 访问被拒绝”错误?

上次更新日期:2020 年 12 月 18 日

我使用 Amazon Simple Storage Service (Amazon S3) 存储桶作为我的 Amazon CloudFront 分配源。我使用 S3 REST API 终端节点作为源域名。为什么 CloudFront 从 Amazon S3 返回“403 访问被拒绝”错误?

简短描述

要解决“访问被拒绝”错误,您必须知道分配源的源域名是 S3 网站终端节点还是 S3 REST API 终端节点。按照以下步骤来确定终端节点类型:

  1. 打开 CloudFront 控制台
  2. 选择您的 CloudFront 分配,然后选择 Distribution Settings(分配设置)。
  3. 选择 Origins and Origin Groups(源和源组)选项卡。
  4. 查看源域名和路径下的域名。然后,根据域名的格式确定终端节点类型。

REST API 终端节点使用以下格式:

DOC-EXAMPLE-BUCKET.s3.amazonaws.com

静态网站终端节点使用以下格式:

DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com

如果您的分配使用 S3 静态网站终端节点,请参阅我使用 S3 网站终端节点作为我的 CloudFront 分配源。为什么我会收到“403 访问被拒绝”错误?

如果您的分配使用 REST API 终端节点,请确认您的配置是否符合以下要求,以免出现“访问被拒绝”错误:

  • 如果您未配置源访问身份 (OAI),则对象必须可以公开访问,或可以使用 AWS 签名版本 4 请求。
  • 存储桶中的对象无法使用 AWS Key Management Service (AWS KMS) 加密。
  • S3 存储桶策略必须允许访问 s3:GetObject。
  • 如果存储桶策略授予访问权限,则拥有 S3 存储桶的 AWS 账户还必须拥有该对象。
  • 请求的对象必须存在于 S3 存储桶中。
  • 如果客户端请求分配的根目录,则您必须定义默认的根对象。
  • 如果您配置了 OAI,则 S3 存储桶策略必须包含 OAI。
  • 如果您没有配置 OAI,则必须在存储桶上禁用 Amazon S3 阻止公开访问。

解决方法

如果您未配置 OAI,则对象必须可以公开访问,或可以使用 AWS 签名版本 4 请求

如果您未配置 OAI,则使用 REST API 终端节点的分配仅支持公开对象,或仅支持使用 AWS 签名版本 4 身份验证请求的对象。

要确定 S3 存储桶中的对象是否可以公开访问,请在 Web 浏览器中打开 S3 对象的 URL。或者对 URL 运行 curl 命令。

下面是 S3 对象的示例 URL:

http://DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com/index.html

如果 Web 浏览器或 curl 命令返回“访问被拒绝”错误,则该对象不可公开访问。如果对象不可公开访问,请使用以下某项配置:

存储桶中的对象无法进行 AWS KMS 加密

CloudFront 分配不支持 AWS KMS 加密对象。您必须从要使用分配提供服务的 S3 对象中删除 KMS 加密。

注意:您可以使用 AES-256 加密您的对象,而不是使用 AWS KMS 加密。

使用下述方法之一来检查您存储桶中的对象是否为 KMS 加密对象:

要使用 Amazon S3 控制台更改对象的加密设置,请参阅如何为 S3 对象添加加密?

要使用 AWS CLI 更改对象的加密设置,您必须先确认该对象的存储桶没有默认加密。如果存储桶没有默认加密,请运行以下 AWS CLI 命令,通过将对象复制到其本身来删除对象的加密。

aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html s3://DOC-EXAMPLE-BUCKET/index.html --storage-class STANDARD

注意:确保将示例命令中的 --storage-class 值更改为适用于您的使用案例的存储类别。将对象复制到其自身会删除 storage-classwebsite-redirect-location 的设置。要在新对象中保留这些设置,请务必在复制请求中明确指定 storage-classwebsite-redirect-location 的值。

S3 存储桶策略必须允许访问 s3:GetObject

要使用具有 S3 REST API 终端节点的分配,您的存储桶策略必须允许公共用户或 CloudFront 的 OAI 访问 s3:GetObject。

即使您的存储桶策略中有 s3:GetObject 的显式允许语句,也请确认没有冲突的显式拒绝语句。显式拒绝语句始终覆盖显式允许语句。

请按照以下步骤查看您的 s3:GetObject 存储桶策略:

1.    从 Amazon S3 控制台打开您的 S3 存储桶。

2.    选择权限选项卡。

3.    选择存储桶策略

4.    查看存储桶策略,查找包含 "Action": "s3:GetObject""Action": "s3:*" 的语句。

在以下示例策略中,有一个允许语句会授予 CloudFront OAI 访问 s3:GetObject. 的权限。还有一个允许语句会授予 s3:GetObject 的公开访问权限。但是,有一个阻止访问 s3: GetObject 的显式拒绝语句,除非请求来自特定 Amazon Virtual Private Cloud (Amazon VPC)。

{
  "Version": "2008-10-17",
  "Id": "PolicyForCloudFrontPrivateContent",
  "Statement": [{
      "Sid": "Allow-OAI-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EAF5XXXXXXXXX"
      },
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ]
    },
    {
      "Sid": "Allow-Public-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ]
    },
    {
      "Sid": "Access-to-specific-VPCE-only",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:sourceVpce": "vpce-1a2b3c4d"
        }
      }
    }
  ]
}

5.    修改存储桶策略,以删除或编辑阻止 CloudFront OAI 访问或公开访问 s3:GetObject 的语句。

注意:CloudFront 可将“访问被拒绝”错误的结果缓存最多 5 分钟。从存储桶策略删除拒绝语句后,您可以在您的分配上运行失效以从缓存中删除对象。

如果存储桶策略授予访问权限,则拥有 S3 存储桶的 AWS 账户还必须拥有该对象

对于应用于外部账户或服务的存储桶策略(例如,公开读取访问或 OAI),拥有存储桶的 AWS 账户也必须拥有这些对象。存储桶或对象归创建该存储桶或对象的 AWS Identity and Access Management (IAM) 身份所属的账户所有。

注意:对象所有权要求适用于存储桶策略授予的访问权限。它不适用于对象的访问控制列表 (ACL) 授予的访问权限。

按照以下步骤检查存储桶和对象的拥有者是否相同:

1.    运行以下 AWS CLI 命令以获得存储桶拥有者的 S3 规范 ID:

aws s3api list-buckets --query Owner.ID

2.    运行以下命令以获得对象拥有者的 S3 规范 ID。

注意:此示例显示的是单个对象,但您可以使用此列表命令来检查多个对象。

aws s3api list-objects --bucket DOC-EXAMPLE-BUCKET --prefix index.html

3.    如果规范 ID 不匹配,则该存储桶和对象的拥有者不同。

注意:您也可以使用 Amazon S3 控制台来检查存储桶和对象拥有者。拥有者可从相应存储桶或对象的权限选项卡中找到。

按照以下步骤将对象的拥有者更改为存储桶拥有者:

1.    从对象所有者的 AWS 账户中运行以下命令,以检索分配给该对象的访问控制列表 (ACL) 权限:

aws s3api get-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name

2.    如果对象具有 bucket-owner-full-control ACL 权限,则跳至步骤 3。如果对象没有 bucket-owner-full-control ACL 权限,则通过对象拥有者的账户运行以下命令:

aws s3api put-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name --acl bucket-owner-full-control

3.    从存储桶拥有者的账户,运行此命令以通过将对象复制到其本身来更改对象的拥有者:

aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html s3://DOC-EXAMPLE-BUCKET/index.html --storage-class STANDARD

注意:确保将示例命令中的 --storage-class 值更改为适用于您的使用案例的存储类别。

请求的对象必须存在于存储桶中

如果用户没有 s3:ListBucket 权限,则用户会因对象缺失遇到“访问被拒绝”错误,而不是“404 未找到”错误。运行 head-object AWS CLI 命令以检查存储桶中是否存在某对象。

注意:请确保发送到 CloudFront 的对象请求与 S3 对象名称完全匹配。S3 对象名称区分大小写。如果请求没有正确的对象名称,则 Amazon S3 响应就会像对象缺失一样。要确定 CloudFront 正在从 Amazon S3 请求哪个对象,可使用服务器访问日志记录

如果存储桶中存在该对象,则“访问被拒绝”错误不会屏蔽“404 未找到”错误。验证其他配置要求以解决“访问被拒绝”错误。

如果存储桶中不存在该对象,则“访问被拒绝”错误将屏蔽“404 未找到”错误。解决与对象缺失相关的问题。

注意:启用公开 s3:ListBucket 访问权限不是安全最佳实践。启用公开 s3:ListBucket 访问权限会允许用户查看和列出存储桶中的所有对象。这将向用户公开对象元数据详细信息(例如,密钥和大小),即使用户没有下载相应对象的权限。

如果客户端请求分配的根目录,则您必须定义默认的根对象

如果您的分配没有定义默认的根对象,并且请求者没有 s3:ListBucket 访问权限,则请求者会收到“访问被拒绝”错误。请求者在请求分配的根目录时会收到此错误,而不是“404 未找到”错误。

要定义默认的根对象,请参阅指定默认根对象

注意:启用公开 s3:ListBucket 访问权限不是安全最佳实践。启用公开 s3:ListBucket 访问权限会允许用户查看和列出存储桶中的所有对象。这将向用户公开对象元数据详细信息(例如,密钥和大小),即使用户没有下载相应对象的权限。

如果您配置了 OAI,则 S3 存储桶策略必须包含 OAI

如果您向 CloudFront 分配添加了 OAI,则还必须在 S3 存储桶策略中添加 OAI 允许语句。

要确认您的存储桶策略是否允许 OAI,请在 Amazon S3 控制台中打开 S3 存储桶。然后,选择权限选项卡并查看存储桶策略。以下是 OAI 的允许语句示例:

{
  "Sid": "1",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EAF5XXXXXXXXX"
  },
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
}

要使用 CloudFront 控制台更新存储桶策略,请按照下列步骤操作:

  1. 打开 CloudFront 控制台,然后选择您的分配。
  2. 选择 Origins and Origin Groups(源和源组)选项卡。
  3. 选择 S3 源,然后选择编辑
  4. 对于 Restrict Bucket Access (限制存储桶访问权限),选择
  5. 对于来源访问标识,选择现有身份或创建一个新身份。
  6. 对于 Grant Read Permissions on Bucket (授予存储桶的读取权限),选择 Yes, Update Bucket Policy (是,更新存储桶策略)。
  7. 选择是,编辑

如果您没有配置 OAI,则必须在存储桶上禁用 Amazon S3 阻止公开访问

如果分配未使用 OAI,并且未使用 AWS 签名版本 4 请求对象,则使用 REST API 终端节点的分配仅支持可公开读取的对象。这意味着,您必须确认存储桶没有应用任何 Amazon S3 阻止公开访问设置。这些设置会覆盖允许公开读取访问的权限。“Amazon S3 阻止公开访问”设置可以应用于各个存储桶或 AWS 账户。