You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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角色上传的差异
  1. 默认ACL设置

    • 控制台上传:默认对象ACL为public-read(存储桶允许公共访问时),或根据存储桶「对象所有权」设置,默认是bucket-owner-full-control。
    • EC2角色上传:代码未指定ACL时,对象继承存储桶默认ACL;若存储桶私有,对象默认仅桶所有者和上传者有权访问。
  2. 对象所有权归属

    • 控制台上传:若存储桶开启「桶所有者强制」,对象所有者为桶所有者。
    • EC2角色上传:若EC2角色属于跨账户,对象所有者默认是上传账户;需在PutObject时指定BucketOwnerFullControlACL,或开启存储桶「桶所有者强制」,才能让桶所有者获得控制权。
  3. 元数据与请求头

    • 控制台上传:会自动添加x-amz-meta-uploaded-via等默认元数据,不影响访问权限。
    • EC2角色上传:仅包含代码中指定的元数据(如ContentType),无额外默认元数据。
  4. 加密配置

    • 两者无差异:若存储桶开启默认服务器端加密,控制台和EC2上传的对象都会自动使用AES256加密(与head-object结果一致)。

内容的提问来源于stack exchange,提问作者Artur Uvarov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:38:27