AWS Java SDK v2生成S3预签名URL访问被拒绝问题
问题根因
AWS SDK for Java 2.x版本生成预签名URL返回AccessDenied的核心原因是S3Presigner实例未配置与S3Client一致的访问凭证。
查看提供的ConnectionProvider实现:构建S3Client时手动传入了配置项中的AK/SK静态凭证,但构建S3Presigner时仅设置了区域参数,未传入自定义凭证提供器,S3Presigner会默认走全局凭证链加载凭证(包括环境变量、系统属性、本地凭证文件、云主机实例角色等来源)。如果默认凭证链加载到的身份不具备目标S3存储桶的对象读取权限,生成的预签名URL自然会被拒绝访问。切换v1版本SDK可正常访问,是因为v1客户端构建逻辑默认复用了上传操作使用的AK/SK凭证,权限匹配。
另外现有getS3Presigner方法存在逻辑缺陷:区域参数判空分支执行后未加返回逻辑,即使区域为空执行了默认创建逻辑,后续仍会执行带区域参数的构建逻辑,空值场景下会直接抛出运行时异常。
修复方案
修正ConnectionProvider中的getS3Presigner方法,保持与S3Client完全一致的凭证、区域加载逻辑,修复后代码如下:
public S3Presigner getS3Presigner() { if (presigner == null) { // 配置项为空时走默认凭证链 if (isNullOrEmpty(s3AccessKey) || isNullOrEmpty(s3SecretKey) || isNullOrEmpty(region)) { presigner = S3Presigner.create(); return presigner; } // 配置项存在时使用与S3Client相同的静态凭证和区域配置 AwsCredentialsProvider credential = StaticCredentialsProvider .create(AwsBasicCredentials.create(s3AccessKey, s3SecretKey)); presigner = S3Presigner.builder() .region(Region.of(region)) .credentialsProvider(credential) .build(); return presigner; } return presigner; }
补充排查项
如果修正代码后仍存在访问被拒问题,按以下顺序核对配置:
- 确认配置的AK/SK对应的IAM身份已绑定目标S3存储桶的
s3:GetObject权限,且不存在显式Deny策略拦截访问 - 确认S3存储桶未使用自定义KMS密钥加密:如果开启了客户管理型KMS密钥加密,生成预签名URL的身份还需要具备
kms:Decrypt权限,否则会返回权限错误 - 确认预签名URL的过期时间设置符合规则:如果使用STS临时凭证生成预签名URL,有效期不能超过临时凭证本身的剩余有效时长
- 确认存储桶策略、对象ACL未设置访问来源限制:比如配置了仅允许指定IP、VPC访问的规则,访问预签名URL的客户端不在允许范围内也会被拦截
内容的提问来源于stack exchange,提问作者Sabu Shakya
相关产品推荐
相关产品推荐

