我使用 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 终端节点。按照以下步骤来确定终端节点类型:
- 打开 CloudFront 控制台。
- 选择您的 CloudFront 分配,然后选择 Distribution Settings(分配设置)。
- 选择 Origins and Origin Groups(源和源组)选项卡。
- 查看源域名和路径下的域名。然后,根据域名的格式确定终端节点类型。
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 命令返回“访问被拒绝”错误,则该对象不可公开访问。如果对象不可公开访问,请使用以下某项配置:
- 创建允许对存储桶中的所有对象进行公开读取访问的存储桶策略。
- 使用 Amazon S3 控制台允许对该对象进行公开读取访问。
- 使用 REST API 终端节点为分配配置 OAI。
- 使用 AWS 签名版本 4 对 Amazon S3 的请求进行身份验证。
存储桶中的对象无法进行 AWS KMS 加密
CloudFront 分配不支持 AWS KMS 加密对象。您必须从要使用分配提供服务的 S3 对象中删除 KMS 加密。
注意:您可以使用 AES-256 加密您的对象,而不是使用 AWS KMS 加密。
使用下述方法之一来检查您存储桶中的对象是否为 KMS 加密对象:
- 使用 Amazon S3 控制台来查看对象属性。查看加密对话框。如果已选中 AWS-KMS,则对象已进行 KMS 加密。
- 您可以使用 AWS 命令行界面 (AWS CLI) 运行 head-object 命令。如果命令返回的 ServerSideEncryption 为 aws:kms,则表明对象已进行 KMS 加密。
注意:如果在运行 AWS CLI 命令时收到错误,请确保您使用的是最新版本的 AWS CLI。
要使用 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-class 和 website-redirect-location 的设置。要在新对象中保留这些设置,请务必在复制请求中明确指定 storage-class 或 website-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 控制台更新存储桶策略,请按照下列步骤操作:
- 打开 CloudFront 控制台,然后选择您的分配。
- 选择 Origins and Origin Groups(源和源组)选项卡。
- 选择 S3 源,然后选择编辑。
- 对于 Restrict Bucket Access (限制存储桶访问权限),选择是。
- 对于来源访问标识,选择现有身份或创建一个新身份。
- 对于 Grant Read Permissions on Bucket (授予存储桶的读取权限),选择 Yes, Update Bucket Policy (是,更新存储桶策略)。
- 选择是,编辑。
如果您没有配置 OAI,则必须在存储桶上禁用 Amazon S3 阻止公开访问
如果分配未使用 OAI,并且未使用 AWS 签名版本 4 请求对象,则使用 REST API 终端节点的分配仅支持可公开读取的对象。这意味着,您必须确认存储桶没有应用任何 Amazon S3 阻止公开访问设置。这些设置会覆盖允许公开读取访问的权限。“Amazon S3 阻止公开访问”设置可以应用于各个存储桶或 AWS 账户。