使用Serverless部署的Lambda向S3执行PutObject时返回AccessDenied错误
可能成因
- 新S3桶默认启用了对象所有权强制规则:2023年4月后AWS新创建的S3桶默认禁用ACL、启用桶所有者强制控制,旧桶创建时该规则未默认启用,若上传逻辑隐含ACL相关操作会被直接拒绝。
- VPC S3端点策略限制:你的Lambda部署在VPC内,访问S3默认走VPC端点,若端点策略仅允许访问旧桶,新桶未加入允许列表时会被拒绝。
- 新桶默认启用自定义KMS加密:若新桶开启了SSE-KMS默认加密,且Lambda执行角色没有对应KMS密钥的
kms:GenerateDataKey、kms:Decrypt权限,会返回AccessDenied,旧桶如果使用S3托管密钥(SSE-S3)则不需要额外KMS权限。 - 新桶桶策略存在显式拒绝:桶策略的优先级高于IAM角色权限,若新桶桶策略存在针对该Lambda角色的Deny规则,即使IAM角色配置了全量S3权限也会被拒绝。
- IAM角色配置未实际生效:修改serverless.yml后未执行重新部署,Lambda的执行角色权限没有更新到最新配置。
排查步骤
- 验证IAM角色权限:进入AWS控制台找到该Lambda的执行角色,使用IAM策略模拟器测试角色对新桶执行
s3:PutObject操作是否被允许,确认权限配置已经同步到AWS。 - 检查新桶配置:
- 查看桶的「对象所有权」设置,确认是否开启了强制ACL禁用规则
- 查看桶的默认加密配置,确认是否使用了自定义KMS密钥
- 查看桶策略,排查是否有针对Lambda角色的显式拒绝规则
- 查看桶的「阻止公共访问」配置,确认没有和上传逻辑冲突的规则
- 检查VPC S3端点配置:查看VPC关联的S3端点访问策略,确认新桶ARN已经被加入允许访问的资源列表。
- 开启S3访问日志:给新桶开启访问日志,查看请求的具体错误码,定位拒绝的直接原因。
解决方案
根据排查到的原因对应处理即可,常见修复方式如下:
- 适配新桶对象所有权规则:在serverless.yml的新桶配置中添加所有权控制规则,匹配旧桶的配置:
BucketNew: Type: 'AWS::S3::Bucket' Properties: BucketName: ${self:custom.bucketNew} OwnershipControls: Rules: - ObjectOwnership: BucketOwnerPreferred # 按需调整公共访问阻止配置,和旧桶保持一致即可 PublicAccessBlockConfiguration: BlockPublicAcls: false BlockPublicPolicy: false IgnorePublicAcls: false RestrictPublicBuckets: false
- 补充KMS权限:如果新桶使用自定义KMS加密,给Lambda执行角色添加对应KMS密钥的使用权限:
# 加到iam.role.statements列表中 - Effect: 'Allow' Action: - 'kms:Decrypt' - 'kms:GenerateDataKey' Resource: 'arn:aws:kms:eu-west-1:<你的AWS账号ID>:key/<KMS密钥ID>'
- 更新VPC S3端点策略:将新桶ARN添加到端点的允许资源列表中。
- 重新部署生效:每次修改serverless.yml后执行
sls deploy,确保所有配置同步到AWS。
内容的提问来源于stack exchange,提问作者Robert Samarji
相关产品推荐
相关产品推荐

