EC2托管网站访问S3公开URL返回403 Forbidden问题排查
问题:S3存储桶GET请求返回403 Forbidden,无法加载FontAwesome CSS文件
我正在开发一个Web应用,需要从Amazon S3获取自托管的FontAwesome资源(CSS文件),引入标签如下:
<link rel="stylesheet" href="https://docsbymario-env.s3.eu-north-1.amazonaws.com/fontawesome/css/all.min.css?v=1.0">
但浏览器控制台中,该GET请求返回403 Forbidden状态码。
我的S3存储桶策略明确允许托管网站的EC2实例(由Beanstalk环境创建)以及用于CodePipeline的IAM角色访问,策略语句如下:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowListBucketToRole", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::390527449299:role/DocsByMarioRole" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::docsbymario-env" }, { "Sid": "AllowReadAccessToRole", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::390527449299:role/DocsByMarioRole" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::docsbymario-env/*" }, { "Sid": "AllowListBucketToIPs", "Effect": "Allow", "Principal": "*", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::docsbymario-env", "Condition": { "IpAddress": { "aws:SourceIp": [ "13.51.220.94/32", "16.16.36.18/32" ] } } }, { "Sid": "AllowReadAccessToIP", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::docsbymario-env/*", "Condition": { "IpAddress": { "aws:SourceIp": [ "13.51.220.94/32", "16.16.36.18/32" ] } } } ] }
上述两个IP地址是我要加载CSS文件的EC2实例的公网IP。
我已为S3存储桶开启公共访问,CodePipeline可通过指定角色正常访问存储桶,但EC2无法通过上述基于IP的存储桶策略访问。
我曾认为是CORS相关问题,因此为存储桶添加了CORS策略:
[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "GET" ], "AllowedOrigins": [ "http://docsbymario.com", "http://api.docsbymario.com" ], "ExposeHeaders": [ "ETag" ], "MaxAgeSeconds": 3000 } ]
其中两个域名实际指向上述两个公网IP,但问题仍未解决。
请问可能的问题是什么?
可能的排查方向
- 源IP匹配错误:浏览器从EC2上的网站加载CSS时,请求的源IP是访问网站的用户客户端IP,而非EC2的公网IP。你存储桶策略里限制的是EC2的IP,自然匹配不上,导致403。
- 单个对象权限未开放:存储桶策略允许访问,但
all.min.css文件的ACL可能还是私有状态。检查该文件的对象权限,确认是否允许公共读取或对应角色/IP访问。 - 存在其他权限冲突:AWS权限遵循“隐式拒绝”原则,如果账户有服务控制策略(SCP)或其他IAM策略限制了S3的
GetObject操作,会覆盖当前存储桶策略的允许规则,需要排查这类限制。 - 缓存导致的旧响应:之前的403响应可能被浏览器或CDN缓存,清除浏览器缓存或强制刷新页面后重试。
- CORS策略未覆盖实际请求源:如果用户是用IP直接访问网站而非设置的域名,请求的Origin就不在
AllowedOrigins列表中,虽然这一般是CORS报错而非403,但也可以确认请求头里的Origin值是否匹配。
内容的提问来源于stack exchange,提问作者Mario Mateaș
相关产品推荐
相关产品推荐

