Lambda生成S3预签名URL本地正常,部署后提示Access Denied求助
这种本地跑起来顺风顺水,一部署到AWS就报access denied的情况我碰到过好多次,核心问题基本都是本地环境和云端环境的权限/配置差异,给你拆解几个最常见的排查方向:
1. Lambda执行角色的S3权限不足
本地调用Serverless函数时,默认用的是你本地AWS凭证(比如~/.aws/credentials里的账号),这个账号大概率有S3的全权限或者足够的访问权限。但部署到云端后,Lambda用的是Serverless自动创建(或你指定)的执行角色,这个角色很可能没被授予生成预签名URL所需的权限。
预签名URL用于下载文件的话,需要Lambda角色拥有s3:GetObject权限。解决方法:
- 打开IAM控制台,找到你的Lambda执行角色
- 添加一条权限策略,示例如下(替换成你的桶名):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::your-bucket-name/*" } ] }
建议限定具体的对象路径,不要给全桶权限,更安全。
2. S3桶策略拦截了Lambda角色的访问
就算Lambda角色有IAM权限,如果S3桶的桶策略里有Deny语句,也会直接覆盖IAM的Allow权限,导致访问被拒绝。很多桶为了安全会设置白名单,只有特定实体能访问。
解决方法:
- 进入S3控制台,找到目标桶的“权限”标签,查看桶策略
- 检查是否有针对Lambda角色ARN的
Deny规则,或者是否没有把Lambda角色加入允许列表 - 调整桶策略,把Lambda角色的ARN添加到允许访问的实体中
3. 代码硬编码了本地凭证(踩过这个坑的举手🙋)
如果你的代码里不小心硬编码了本地的AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY,那本地调用时没问题,但部署到Lambda后,生成的预签名URL会用本地凭证。如果这个本地凭证没有云端S3的访问权限,或者被桶策略拒绝,就会报错。
解决方法:
- 删掉代码里的硬编码凭证,让AWS SDK自动获取Lambda的临时凭证(AWS SDK v2/v3都会自动读取Lambda环境中的临时凭证,不用手动配置)
4. S3对象的所有权/ACL设置问题
如果S3对象是由其他AWS账户上传的,或者对象的ACL设置为私有,就算桶权限没问题,Lambda角色也可能无法访问。
解决方法:
- 检查对象的ACL,确认是否允许Lambda执行角色访问
- 开启桶的“对象所有权控制”为桶所有者优先,这样桶所有者(你的账户)的IAM权限会覆盖对象的ACL权限,避免跨账户上传的权限问题
5. Serverless框架的Stage/配置差异
有时候你本地调用用的是--stage dev,部署时用了--stage prod,不同Stage对应的桶名、角色配置可能不一样。另外serverless-offline插件的模拟环境会忽略部分权限检查,导致本地正常但云端报错。
解决方法:
- 核对
serverless.yml里的配置,确保部署的Stage对应的桶名、角色权限正确 - 用
serverless info命令查看部署后的Lambda角色ARN,再去IAM验证权限是否匹配
先从Lambda角色权限和桶策略开始排查,这两个是最常见的问题!
内容的提问来源于stack exchange,提问作者user3163545

