AWS CloudFront可访问手动上传S3对象,后端传图报Access Denied
问题描述
我配置了以S3存储桶为源的CloudFront分发,该分发已部署并处于活跃状态——通过distributionUrl/filename可访问S3中手动上传(如根对象、控制台上传文件)的内容。
我使用Golang后端上传文件至该S3存储桶,上传操作成功,但通过CloudFront访问这些文件时却出现Access Denied错误。文件路径一致,且通过AWS CLI对比ACL(包括所有者)均无差异。
上传代码:
object, err = svc.PutObject(&s3.PutObjectInput{ Bucket: aws.String(bucketName), Key: aws.String(fileName), Body: file, ContentType: aws.String("image/jpeg"), })
aws s3api head-object执行结果:
{ "AcceptRanges": "bytes", "LastModified": "", "ContentLength": 124572, "ETag": "\"b0d4cc1205832ef077cde2c37da505fb\"", "ContentType": "image/jpeg", "ServerSideEncryption": "AES256", "Metadata": {} } { "AcceptRanges": "bytes", "LastModified": "", "ContentLength": 545, "ETag": "\"856fdf932c9e9d3d8dbf9bb3771117e9\"", "ContentType": "text/html", "ServerSideEncryption": "AES256", "Metadata": {} }
需排查的关键点
1. CloudFront源访问控制(OAC/OAI)权限
- 确认CloudFront使用的OAC(Origin Access Control)或OAI(Origin Access Identity)是否被授予S3存储桶的
s3:GetObject权限。如果是新创建的分发,默认用OAC,检查存储桶策略是否包含允许OAC访问的语句:{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::YOUR_ACCOUNT_ID:distribution/YOUR_DISTRIBUTION_ID" } } } ] } - 注意:存储桶策略与ACL的权限逻辑是累加且需同时满足,确保没有冲突的拒绝策略。
2. S3对象默认ACL配置
- 控制台上传文件时,默认会设置对象ACL为
public-read(若存储桶允许公共访问),而你的Golang代码未指定ACL参数,对象会继承存储桶的默认ACL。如果存储桶默认私有,CloudFront的OAC/OAI可能无读取权限。 - 可在PutObject时显式指定ACL为
aws.String("bucket-owner-full-control")或public-read(根据需求),测试是否解决问题。
3. CloudFront缓存与刷新
- 若之前访问该路径返回过Access Denied,CloudFront可能缓存了错误响应。手动刷新该文件缓存:在CloudFront控制台进入分发的「Invalidations」选项卡,添加路径
/filename。 - 检查缓存策略是否允许CloudFront缓存403响应,若有需要调整错误缓存TTL。
4. S3版本控制影响
- 若存储桶开启版本控制,确认访问的是正确版本的对象。上传后可能生成新版本,但CloudFront请求的是缓存的旧版本,或旧版本权限存在问题。
5. 对象路径大小写与编码
- S3对象键大小写敏感,检查CloudFront请求路径与Golang上传的
fileName是否完全一致,包括大小写、特殊字符编码情况。控制台上传会自动编码特殊字符,需确认代码中是否做了相同处理。
6. IAM角色权限(EC2端)
- 虽然上传成功,但确认EC2的IAM角色是否拥有
s3:PutObjectAcl权限(若后续需修改对象ACL)。当前问题核心是读取权限,重点仍在CloudFront的源访问配置。
控制台上传与EC2角色上传的差异
默认ACL设置
- 控制台上传:默认对象ACL为
public-read(存储桶允许公共访问时),或根据存储桶「对象所有权」设置,默认是bucket-owner-full-control。 - EC2角色上传:代码未指定
ACL时,对象继承存储桶默认ACL;若存储桶私有,对象默认仅桶所有者和上传者有权访问。
- 控制台上传:默认对象ACL为
对象所有权归属
- 控制台上传:若存储桶开启「桶所有者强制」,对象所有者为桶所有者。
- EC2角色上传:若EC2角色属于跨账户,对象所有者默认是上传账户;需在PutObject时指定
BucketOwnerFullControlACL,或开启存储桶「桶所有者强制」,才能让桶所有者获得控制权。
元数据与请求头
- 控制台上传:会自动添加
x-amz-meta-uploaded-via等默认元数据,不影响访问权限。 - EC2角色上传:仅包含代码中指定的元数据(如
ContentType),无额外默认元数据。
- 控制台上传:会自动添加
加密配置
- 两者无差异:若存储桶开启默认服务器端加密,控制台和EC2上传的对象都会自动使用AES256加密(与
head-object结果一致)。
- 两者无差异:若存储桶开启默认服务器端加密,控制台和EC2上传的对象都会自动使用AES256加密(与
内容的提问来源于stack exchange,提问作者Artur Uvarov
相关产品推荐
相关产品推荐

