使用RoleArn连接AWS S3 Client报错,请求排查问题
尝试使用RoleArn替代静态SecretKey和AccessKey连接AWS S3 Client。已为该RoleArn配置信任关系(允许s3.amazonaws.com执行sts:AssumeRole),并附加了包含S3操作权限的策略,但运行时出现无法从任何凭证提供链加载AWS凭证的报错,请问是否存在配置遗漏?
信任关系配置
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "s3.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
S3权限策略
{ ..., { "Action": [ "s3:CreateBucket", "s3:DeleteBucket", "s3:DeleteObject", "s3:Get*", "s3:Put*" ], "Effect": "Allow", "Resource": "arn:aws:s3:::*partOfMyBucketName*" } }
Java配置代码
@Configuration public class AwsS3Configuration { @Value("${aws.roleArn}") private String roleARN; @Bean public AmazonS3 awsS3client() { try { AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard() .withRegion(US_EAST_1) .build(); AssumeRoleRequest roleRequest = new AssumeRoleRequest() .withRoleArn(roleARN) .withRoleSessionName("sessionName"); AssumeRoleResult roleResponse = stsClient.assumeRole(roleRequest); Credentials sessionCredentials = roleResponse.getCredentials(); BasicSessionCredentials awsCredentials = new BasicSessionCredentials( sessionCredentials.getAccessKeyId(), sessionCredentials.getSecretAccessKeyId(), sessionCredentials.getSessionToken() ); return AmazonS3ClientBuilder.standard() .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) .withRegion(US_EAST_1) .build(); } catch (AmazonServiceException e) { e.printStackTrace(); } catch (SdkClientException e) { e.printStackTrace(); } return null; }
报错信息
com.amazonaws.SdkClientException: Unable to load AWS credentials from any provider in the chain: [EnvironmentVariableCredentialsProvider: Unable to load AWS credentials from envrionment variables (AWS_ACCESS_KEY_ID (or AWS_ACCESS_KEY) and AWS_SECRET_KEY (or AWS_SECRET_ACCESS_KEY)), SystemPropertiesCredentialsProvider: Unable to load AWS credentials from Java system properties (aws.accessKeyId and aws.secretKey), WebIdentityTokenCredentialsProvider: Unable to execute HTTP request: Connect to sts.us-east-1.amazonaws.com:443 [sts.us-east-1.amazonaws.com/209.54.177.185] failed: Connect timed out, com.amazonaws.auth.profile.ProfileCredentialsProvider@2de0f3e3: profile file cannot be null, com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper@6f102740: Failed to connect to service endpoint: ]
你的配置存在3个关键问题,直接导致凭证加载失败:
STS客户端缺少初始凭证
你创建的AWSSecurityTokenService客户端未指定凭证提供者,默认走AWS凭证链加载,但你的环境中没有任何可用凭证(从报错可见环境变量、系统属性、配置文件、EC2元数据均无有效凭证),连STS服务都无法访问,自然无法调用assumeRole获取临时凭证。信任关系配置错误
当前信任关系允许s3.amazonaws.com服务角色扮演该角色,但你的场景是Java应用主动调用STS AssumeRole,并非S3服务自身需要扮演角色。因此Principal应改为应用所在环境的身份(如EC2实例角色、IAM用户ARN、跨账号的账号ID等),而非s3.amazonaws.com。未处理临时凭证过期
临时凭证默认有效期1小时,当前代码手动获取的凭证过期后,S3客户端会直接失效,没有自动刷新机制。
修复方案
方案1:使用IAM角色(推荐,适用于AWS环境内运行)
如果应用在AWS环境(EC2、ECS、EKS、Lambda等)运行,直接给运行环境绑定拥有S3操作权限的IAM角色,无需手动调用AssumeRole。S3客户端可简化为:
@Bean public AmazonS3 awsS3client() { return AmazonS3ClientBuilder.standard() .withRegion(US_EAST_1) .build(); }
客户端会自动从环境获取IAM角色的临时凭证,并自动处理凭证刷新。
方案2:正确配置AssumeRole(适用于非AWS环境或跨账号场景)
若必须使用AssumeRole,需完成以下调整:
- 修正信任关系:将Principal改为允许你的源身份,例如允许某个IAM用户扮演该角色:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::你的账号ID:user/用户名" }, "Action": "sts:AssumeRole" } ] }
- 给STS客户端提供初始凭证:比如通过环境变量初始化STS客户端:
AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard() .withRegion(US_EAST_1) .withCredentials(new EnvironmentVariableCredentialsProvider()) .build();
- 自动处理凭证过期:使用
STSAssumeRoleSessionCredentialsProvider自动刷新临时凭证,替代手动调用AssumeRole:
@Bean public AmazonS3 awsS3client() { STSAssumeRoleSessionCredentialsProvider credentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(roleARN, "sessionName") .withRegion(US_EAST_1) .build(); return AmazonS3ClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(US_EAST_1) .build(); }
方案3:检查网络连接
报错提到连接STS服务超时,需确保应用所在环境能访问sts.us-east-1.amazonaws.com的443端口,无防火墙或代理拦截。
内容的提问来源于stack exchange,提问作者Karol Katanowski

