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

4 分钟阅读
0

我正在使用 Amazon Simple Storage Service(Amazon S3)存储桶作为我的 Amazon CloudFront 分配的来源。我正在使用 S3 REST API 端点作为源域名。CloudFront 从 Amazon S3 返回 403 访问被拒绝错误。

简短描述

要排查访问被拒绝错误,请确定您的分配的源域名是 S3 网站端点还是 S3 REST API 端点。请按照下面的步骤查找端点类型:

1.    打开 CloudFront 控制台

2.    选择您的 CloudFront 分配。然后,选择分配设置

3.    选择源和源组选项卡。

4.    在源域名和路径下查看域名。然后,根据域名的格式确定端点类型。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 访问被拒绝错误。有关更多信息,请参阅I’m using an S3 website endpoint as the origin of my CloudFront distribution。为什么我会收到 403 Access Denied(访问被拒绝)错误?

如果您的分配使用 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,则必须在 S3 存储桶策略中包含 CloudFront 服务主体。如果配置了 OAI,则必须在 S3 存储桶策略中包含该 OAI。
  • 如果未配置 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 密钥提供服务

使用以下方法之一检查存储桶中的对象是否经过 AWS KMS 加密:

  • 使用 Amazon S3 控制台查看对象的属性。查看“加密”对话框。如果选择了 AWS KMS,则对象是经过 AWS KMS 加密的。
  • 使用 AWS 命令行界面(AWS CLI)运行 head-object 命令。如果该命令以 aws:kms 的形式返回 ServerSideEncryption,则对象是经过 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.    选择“权限”选项卡。

3.    选择存储桶策略。

4.    查看存储桶策略中是否有带 "Action": "s3:GetObject""Action": "s3:*" 的语句。下面的示例策略包括一个允许语句,其授予 CloudFront OAC 对 s3:GetObject 的访问权限。它还包括一个授予 CloudFront OAI 对 s3:GetObject 的访问权限的语句和一个授予对 s3:GetObject 的公共访问权限的允许语句。但是,s3:GetObject 有一个显示拒绝语句,它会阻止访问,除非请求来自特定 Amazon Virtual Private Cloud(Amazon VPC):

{
  "Version": "2012-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 会将访问被拒绝错误的结果缓存长达五分钟。从存储桶策略中删除拒绝语句后,您可以在您的分配上运行失效操作,以从缓存中删除对象。

S3 存储桶和对象的所有权

要将存储桶策略应用于外部账户或者服务,拥有该存储桶的 AWS 账户也必须拥有这些对象。存储桶或对象归创建存储桶或对象的 AWS Identity and Access Management(IAM)身份账户所有。

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

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

1.    运行此 AWS CLI 命令以获取存储桶所有者的 S3 规范 ID:

aws s3api list-buckets --query Owner.ID

2.    运行此命令以获取对象所有者的 S3 规范 ID:

**注意:**此示例显示了一个对象,但您可以使用 list 命令来检查多个对象。

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 未找到”错误。

要定义默认根对象,请参阅 Specifying a default root object

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

OAC 或 OAI 的权限

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

要验证您的存储桶策略是否允许 OAI,请在 Amazon S3 控制台中打开您的 S3 存储桶。然后,选择“权限”选项卡并查看存储桶策略。在下面的示例策略中,第一个语句是配置 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.    选择源和源组选项卡。

3.    选择 S3 源,然后选择编辑

4.    对于限制存储桶访问,选择

5.    对于源访问身份,选择现有身份或创建一个新身份。

6.    对于授予对存储桶的读取权限,选择是,更新存储桶策略

7.    选择是,请编辑

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

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


相关信息

对来自源的错误响应进行问题排查

如何对来自 Amazon S3 的 403 访问被拒绝错误执行故障排查?

AWS 官方
AWS 官方已更新 1 年前