Django上传至私有S3桶经CloudFront访问报AccessDenied问题排查
S3私有桶+CloudFront OAI配置问题解答
核心疑问结论
- 你桶里的两条策略本身不存在逻辑冲突,之前出现
AccessDenied的核心原因有两点:一是S3的Block all public access开关优先级高于普通桶策略,会直接拦截所有Principal: "*"的公网授权,那条旧的公网允许规则在开关开启后完全失效;二是你最初手动添加的OAI授权存在配置疏漏(常见为OAI ARN抄写错误、源站未正确绑定对应OAI、策略语法缺漏),导致CloudFront的请求没有命中有效Allow规则。 - 删除原有公网访问策略后问题解决存在必然性:当你通过控制台创建OAI并选择自动更新桶策略时,系统生成的OAI授权规则是完全准确的,此时删除失效的公网规则后,桶内仅保留正确的OAI读权限授权,CloudFront携带OAI身份的请求自然可以正常获取文件。
- 直接通过S3端点访问文件返回
AccessDenied是符合预期的正常状态,这正是你配置私有桶要实现的效果,不需要额外调整。
上传功能不受影响的原因
Wagtail后台上传文件正常,是因为django-storages上传时使用的是你配置的IAM用户/角色密钥,走IAM身份权限校验链路,和桶公网策略、OAI授权无关。只要给django-storages使用的IAM身份授予了s3:PutObject、s3:PutObjectAcl等必要的上传权限,无论桶是否公开、是否开启Block all public access,上传流程都不会异常。
最终可落地配置清单
要稳定实现「Django正常上传媒体文件、仅CloudFront可对外分发文件、S3端点完全禁止公网访问」的效果,按以下规则核对配置即可:
- S3桶侧配置
- 保持Block all public access所有选项全开启
- 桶策略仅保留OAI读权限授权,删除所有
Principal: "*"的公网访问规则,标准策略格式如下:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowCloudFrontOAIReadAccess", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity 替换为你的实际OAI ID" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::替换为你的实际桶名/*" } ] }
- 不需要给桶配置任何其他公网访问相关规则
- CloudFront源站配置
- 源站类型选择原生S3源站,不要配置为自定义源站
- 源站访问身份选择对应OAI,不要选择公网访问模式
- 开启自动更新桶策略选项,避免手动抄写策略出现格式错误
- Django侧django-storages配置
- 原有S3密钥、桶名、区域等上传相关配置保持不变即可
- 将
AWS_DEFAULT_ACL参数设置为None,不要设置为public-read,避免上传时尝试给对象添加公网读权限触发权限报错
- 配置有效性验证标准
- 直接访问S3文件端点返回403 AccessDenied:配置正常
- 访问CloudFront分发的文件URL可正常加载资源:配置正常
- Wagtail后台上传、编辑、删除媒体文件无报错:配置正常
补充提示:如果需要给运维或管理员开放S3控制台的文件管理权限,单独给对应IAM身份授权即可,不要修改桶公网访问配置。
内容的提问来源于stack exchange,提问作者user1267675
相关产品推荐
相关产品推荐

