AWS S3与Serverless:使用PUT预签名URL时遭遇访问拒绝错误
我来帮你梳理下可能导致这个Access Denied错误的几个常见原因,结合你的代码和配置来看,逐个排查应该能解决问题:
1. IAM角色的资源范围不匹配
你的Lambda IAM角色中,Resource只指定了桶的ARN(!GetAtt galleryBucket.Arn),但s3:PutObject和s3:PutObjectAcl操作是作用在桶内的对象上的,而非桶本身。这会导致Lambda角色没有权限为具体对象生成有效的预签名URL。
解决方案:
修改serverless.yml中的资源配置,添加对象路径通配符:
iamRoleStatements: - Effect: 'Allow' Action: - 's3:PutObject' - 's3:PutObjectAcl' Resource: - !Sub "${galleryBucket.Arn}/*"
这样Lambda角色就拥有了对桶内所有对象的操作权限,生成预签名URL时才能正确授权。
2. S3桶的CORS配置未允许PUT请求
前端向预签名URL发起跨域PUT请求时,S3桶的CORS规则必须明确允许对应的请求方法、来源域名和请求头。如果CORS配置缺失,浏览器会拦截请求,或者S3直接返回权限错误。
解决方案:
在S3控制台的桶权限页面,配置符合你业务需求的CORS规则,比如:
<CORSConfiguration> <CORSRule> <AllowedOrigin>https://your-frontend-domain.com</AllowedOrigin> <!-- 替换为你的前端域名,测试时可临时用* --> <AllowedMethod>PUT</AllowedMethod> <AllowedHeader>Content-Type</AllowedHeader> <MaxAgeSeconds>3000</MaxAgeSeconds> </CORSRule> </CORSConfiguration>
注意:生产环境不要用*作为AllowedOrigin,限制为具体域名更安全;如果请求有自定义头,也要添加到AllowedHeader中。
3. 桶的Block Public Access设置与ACL参数冲突
你在生成预签名URL时指定了ACL: 'public-read',但如果S3桶开启了Block Public Access中的「Block public access to buckets and objects granted through any access control lists (ACLs)」选项,这个设置会直接禁止通过ACL设置对象为公共可读,导致PUT请求被拒绝。
解决方案:
- 如果业务确实需要对象公开可读,可以在S3控制台的桶权限页面,暂时关闭该Block Public Access选项;
- 或者去掉预签名URL中的
ACL: 'public-read'参数,改用其他方式设置对象权限(比如后续通过Lambda调用修改权限,或使用桶策略),保持对象默认的私有权限。
4. PUT请求的Content-Type与预签名URL不匹配
生成预签名URL时你明确指定了ContentType: 'image/jpeg',S3会严格校验PUT请求的Content-Type头是否与预签名URL中的一致,不匹配的话会直接返回Access Denied。
解决方案:
确保前端发起PUT请求时设置相同的Content-Type头,比如用JavaScript的fetch API:
fetch(yourSignedUrl, { method: 'PUT', headers: { 'Content-Type': 'image/jpeg' }, body: yourImageFile })
建议你先从IAM资源范围和CORS配置开始排查,这两个是这类问题最常见的诱因。
内容的提问来源于stack exchange,提问作者Benjamin Sommer

