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

上次更新日期:2022 年 12 月 6 日

我使用 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.    选择源和源组选项卡。

4.    查看 Origin Domain Name and Path(源域名和路径)下的域名。然后,根据域名的格式确定端点类型。REST API 端点使用以下格式:

DOC-EXAMPLE-BUCKET.s3.region.amazonaws.com 
DOC-EXAMPLE-BUCKET.s3.amazonaws.com

重要提示bucket-name.s3.amazonaws.com 格式不适用于 2019 年或之后启动的区域。静态网站端点使用以下格式:

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

如果您的分配使用的是 S3 静态网站端点,则可能会收到“403 访问被拒绝”错误。有关更多信息,请参阅我使用 S3 REST API 端点作为我的 CloudFront 分配来源。为什么我会收到“403 访问被拒绝”错误?

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

  • 如果您未配置来源访问控制(OAC)来源访问身份(OAI),则对象必须可以公开访问。或者,您必须使用 AWS 签名版本 4 请求对象。
  • 如果 S3 存储桶包含由 AWS Key Management Service(AWS KMS)加密的对象,则应使用 OAC,而不是 OAI。
  • S3 存储桶策略必须允许访问 s3:GetObject
  • 如果存储桶策略授予访问权限,则拥有 S3 存储桶的 AWS 账户还必须拥有该对象。
  • 请求的对象必须存在于 S3 存储桶中。
  • 如果客户端请求分配的根目录,则您必须定义默认的根对象。
  • 如果您配置了 OAI,则 S3 存储桶策略必须包含 OAI。
  • 如果您配置了 OAC,则 CloudFront 服务主体必须包含在 S3 存储桶策略中。如果您配置了 OAI,则 OAI 必须包含在 S3 存储桶策略中。
  • 如果您没有配置 OAC 或 OAI,则必须在存储桶上关闭 Amazon S3 屏蔽公共访问权限。

解决方法

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

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

以下是 S3 对象的示例 URL:

https://DOC-EXAMPLE-BUCKET.s3.amazonaws.com/index.html

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

由 AWS Key Management Service(AWS SSE-KMS)加密的对象

如果 s3 存储桶包含由 AWS Key Management Service(AWS SSE-KMS)加密的对象,则应使用 OAC,而不是 OAI。

通过设置 OAC,CloudFront 可以为 AWS KMS 加密的对象提供服务。为此,请向 AWS KMS 密钥策略中添加语句,以授予 CloudFront 服务主体使用该密钥的权限。要在不设置 OAC 的情况下为 AWS KMS 密钥加密对象提供服务,请使用 Lambda@Edge 提供从 S3 存储桶加密的 AWS KMS Key

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

  • 使用 Amazon S3 控制台来查看对象属性。查看加密对话框。如果已选中 AWS-KMS,则对象已进行 AWS KMS 加密。
  • 使用 AWS 命令行界面(AWS CLI)运行 head-object 命令。如果命令返回的 ServerSideEncryption 为 aws:kms,则表明对象已进行 AWS KMS 加密。如果在运行 AWS CLI 命令时收到错误,请确保您使用的是最新版本的 AWS CLI注意:OAI 不支持提供 AWS KMS 加密对象。

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

要使用具有 S3 REST API 端点的分配,您的存储桶策略必须允许公共用户或 CloudFront 的 OAI 访问 s3:GetObject。即使您的存储桶策略中有 s3:GetObject 的显式允许语句,也请确认没有冲突的显式拒绝语句。显式拒绝语句始终覆盖显式允许语句。

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

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

2.    选择“Permissions”(权限)选项卡。

3.    选择“Bucket Policy”(存储桶策略)。

4.    查看存储桶策略,查找包含 "Action": "s3:GetObject""Action": "s3:*" 的语句。以下示例策略包含一个允许语句,用于授予 CloudFront OAI 访问 s3:GetObject 的权限。此外,它还包括一个用于授予 CloudFront OAI 访问 s3:GetObject 权限的语句和一个用于授予公开访问 s3:GetObject 权限的允许语句。但是,有一个阻止访问 s3: GetObject 的显式拒绝语句,除非请求来自特定 Amazon Virtual Private Cloud(Amazon VPC):

{
  "Version": "2008-10-17",
  "Id":
    "PolicyForCloudFrontPrivateContent",
  "Statement": [{
      "Sid": "Allow-OAC-Access-To-Bucket",
        "Effect": "Allow",
        "Principal":
    {
            "Service": "cloudfront.amazonaws.com"
        },
        "Action": "s3:GetObject",
       
    "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
        "Condition": {
            "StringEquals": {
               
    "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
            }
        }
      },
     
    {
      "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 账户必须同时拥有这些对象。存储桶或对象归创建该存储桶或对象的 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 控制台来检查存储桶和对象拥有者。拥有者可从相应存储桶或对象的“Permissions”(权限)选项卡中找到。

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

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 访问权限会允许用户查看和列出存储桶中的所有对象。即使用户没有下载对象的权限,这也会向用户公开对象元数据详细信息(例如,密钥和大小)。

OAC 或 OAI 的权限

如果您配置了 OAC,则 CloudFront 服务主体必须包含在 S3 存储桶策略中。如果您配置了 OAI,则 OAI 必须包含在 s3 存储桶策略中

要确认您的存储桶策略是否允许 OAI,请在 Amazon S3 控制台中打开 S3 存储桶然后,选择“Permissions”(权限)选项卡并查看存储桶策略。在下面的示例策略中,第一个语句是配置 OAC 时针对 CloudFront 服务主体的允许语句。第二个语句是 OAI 的允许语句:

{
      "Sid": "Allow-OAC-Access-To-Bucket",
        "Effect": "Allow",
        "Principal": {
           
    "Service": "cloudfront.amazonaws.com"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
       
    "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
           
    }
     }
      },

{
  "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 源,然后选择 Edit(编辑)。

4.    对于 Restrict Bucket Access(限制存储桶访问权限),选择 Yes(是)。

5.    对于 Origin Access Identity(来源访问标识),选择现有身份或创建一个新身份。

6.    对于 Grant Read Permissions on Bucket (授予存储桶读取权限),选择 Yes, Update Bucket Policy(是,更新存储桶策略)。

7.    选择 Yes, Edit(是,请编辑)。

在没有 OAC 或 OAI 的情况下允许分配公开访问

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