AWS S3预签名URL下载文件返回Access Denied错误排查求助
1. 首先排除@字符URL编码的影响
URL自动将@转义为%40是HTTP标准行为,S3可以正常识别编码后的路径,这个不是导致Access Denied的原因,可以直接排除。
2. 先修正IAM权限配置的错误
你当前的serverless.yml里的IAM配置存在两处可优化/错误点:
- 权限动作
s3:ListObject拼写错误,正确的列桶对象动作是s3:ListBucket,如果你没有列桶的需求可以直接删掉这个无效动作 - 不建议配置
"arn:aws:s3:::*"这种全桶资源权限,风险很高,直接保留你自己的存储桶ARN即可,修正后的权限示例:
iam: role: statements: - Effect: 'Allow' Action: - 's3:GetObject' - 's3:PutObject' - 's3:CreateBucket' Resource: - "arn:aws:s3:::my_bucket/*" - "arn:aws:s3:::my_bucket"
如果需要列桶权限,单独加一条statement,因为ListBucket的作用资源是桶本身,不能作用到对象路径:
- Effect: 'Allow' Action: 's3:ListBucket' Resource: "arn:aws:s3:::my_bucket"
3. 排查其他常见导致Access Denied的原因
- KMS加密权限缺失:如果你的S3桶开启了默认KMS加密,或者目标文件是用KMS密钥加密的,需要给Lambda执行角色添加对应KMS密钥的
kms:Decrypt权限,否则即使有S3 GetObject权限也会报拒绝访问。 - 区域不匹配:生成预签名URL的boto3客户端的区域要和S3桶实际所在区域完全一致,如果你的Lambda部署区域和桶的区域不同,需要在初始化s3客户端时显式指定区域:
s3 = boto3.client('s3', region_name='你的桶所在区域,比如ap-southeast-1')
- URL过期:
generate_presigned_url默认的过期时间是3600秒(1小时),如果超过这个时间再访问就会报错,你可以通过ExpiresIn参数自定义过期时长,最长不超过7天(使用IAM角色签名的情况下)。 - 对象所有权问题:如果目标文件是由其他AWS账号、或者其他身份上传的,没有给你的Lambda执行角色开放读取权限,也会出现拒绝访问,可以检查文件的ACL配置。
- 桶策略限制:检查S3桶本身的桶策略,是否有规则拦截了Lambda角色的访问请求,或者开启了公共访问阻止的相关规则。
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

