This may be a bug, or a misunderstanding of how to use the 2.0 sdk to assume a role with SAML. In short, I would like to use Secure Token Service to authenticate with my Identity Provider and then once authenticated, assume a role in AWS to use when calling different services.
Currently, I am using the StsAssumeRoleWithSamlCredentialProvider. Once I configure the credential provider and give it a mechanism to get a valid saml assertion from my Identity Provider, I should be able to give that credential provider to any other service client so that it will use those credentials when making API calls. Those other services should NOT attempt to get credentials from any other sources ( this includes the DefaultCredentialProvider which looks in a myriad of places).
When I pass the StsAssumeRoleWithSamlCredentialProvider to another service client ( such as CloudWatchLogsClient ), and initiate a request, the request fails with multiple "Unable to load credentials from *" errors. Here is one of the stack traces:
[http-nio-8080-exec-1] DEBUG software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain - Unable to load credentials from SystemPropertyCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId).
software.amazon.awssdk.core.exception.SdkClientException: Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId).
at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:97)
at software.amazon.awssdk.auth.credentials.internal.SystemSettingsCredentialsProvider.resolveCredentials(SystemSettingsCredentialsProvider.java:58)
at software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain.resolveCredentials(AwsCredentialsProviderChain.java:91)
at software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider.resolveCredentials(DefaultCredentialsProvider.java:92)
at software.amazon.awssdk.awscore.client.handler.AwsClientHandlerUtils.createExecutionContext(AwsClientHandlerUtils.java:70)
at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.createExecutionContext(AwsSyncClientHandler.java:68)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:68)
at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:44)
at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:55)
at software.amazon.awssdk.services.sts.DefaultStsClient.assumeRoleWithSAML(DefaultStsClient.java:370)
at software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithSamlCredentialsProvider.getUpdatedCredentials(StsAssumeRoleWithSamlCredentialsProvider.java:69)
at software.amazon.awssdk.services.sts.auth.StsCredentialsProvider.updateSessionCredentials(StsCredentialsProvider.java:68)
at software.amazon.awssdk.utils.cache.CachedSupplier.refreshCache(CachedSupplier.java:132)
at software.amazon.awssdk.utils.cache.CachedSupplier.get(CachedSupplier.java:89)
at software.amazon.awssdk.services.sts.auth.StsCredentialsProvider.resolveCredentials(StsCredentialsProvider.java:78)
at software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithSamlCredentialsProvider.resolveCredentials(StsAssumeRoleWithSamlCredentialsProvider.java:42)
at software.amazon.awssdk.awscore.client.handler.AwsClientHandlerUtils.createExecutionContext(AwsClientHandlerUtils.java:70)
at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.createExecutionContext(AwsSyncClientHandler.java:68)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:68)
at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:44)
at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:55)
at software.amazon.awssdk.services.cloudwatchlogs.DefaultCloudWatchLogsClient.getLogEvents(DefaultCloudWatchLogsClient.java:1836)
at logs.GetAWSLogs.getLogs(GetAWSLogs.java:167)
What I think may be the cause of this issue is that the StsAssumeRoleWithSamlCredentialsProvider uses the StsClient to make the request. The default StsClient uses the DefaultCredentialsProvider to authenticate with AWS in order to make the request. You can override the credentials provider in the StsClient with the overrideConfiguration method, but since the StsAssumeRoleWithSamlCredentialsProvider requires the StsClient, it seems that its a "chicken and egg" scenario. You can't configure the Sts..CredentialsProvider without an StsClient, but the StsClient needs a credentials provider itself...
Guidance on how to correctly assume a role, or if this is truly a bug, then a quick fix would be very much appreciated.
`
ProxyConfiguration proxyConfig = null;
try {
proxyConfig = ProxyConfiguration
.builder()
.endpoint(new URI("http_proxy"))
.build();
} catch (URISyntaxException e) {
e.printStackTrace();
}
AWSSAMLAuthenticationConfiguration config = AWSSAMLAuthenticationConfiguration
.builder()
.userName(ad_user)
.userPass(ad_pass)
.roleName(aws_role)
.region(Region.US_EAST_1)
.proxyConfig(proxyConfig)
.build();
SdkHttpClient httpClient = ApacheHttpClient
.builder()
.proxyConfiguration(proxyConfig)
.build();
AssumeRoleWithSamlRequest request = AssumeRoleWithSamlRequest
.builder()
.durationSeconds(900)
.roleArn(ROLE_ARN)
.principalArn("PRINCIPAL_ARN")
.build();
SamlIdentityProviderServiceFactory factory = new SamlIdentityProviderServiceFactory();
SamlIdentityProviderService service = factory.getService(config);
Supplier<AssumeRoleWithSamlRequest> supplier = () ->
request.toBuilder()
.samlAssertion(service.getValidAssertion())
.build();
cp = StsAssumeRoleWithSamlCredentialsProvider
.builder()
.stsClient(StsClient.builder().region(Region.US_EAST_1).httpClient(httpClient).build())
.asyncCredentialUpdateEnabled(true)
.refreshRequest(supplier)
.build();
cw = CloudWatchLogsClient.builder()
.httpClient(httpClient)
.region(Region.US_EAST_1)
.credentialsProvider(cp)
.build();
GetLogEventsResponse logEventsResponse = cw.getLogEvents(GetLogEventsRequest.builder()
.logGroupName(logGroup)
.logStreamName(logStream)
.startFromHead(true)
.build());
`
Without the ability to correctly assume a role via saml, we cannot migrate to the 2.0 version of the SDK.
@dagnir @millems
Bumping to hopefully get traction...
Can you try configuring the STS client with an AnonymousCredentialsProvider and let me know if that works for you?
So, I changed the following
cp = StsAssumeRoleWithSamlCredentialsProvider
.builder()
.stsClient(StsClient.builder().region(Region.US_EAST_1).httpClient(httpClient).build())
.asyncCredentialUpdateEnabled(true)
.refreshRequest(supplier)
.build();
to
cp = StsAssumeRoleWithSamlCredentialsProvider
.builder()
.stsClient(
StsClient
.builder()
.region(Region.US_EAST_1)
.httpClient(httpClient)
.credentialsProvider(AnonymousCredentialsProvider.create()).build()
)
.asyncCredentialUpdateEnabled(true)
.refreshRequest(supplier)
.build();
And instead of getting the previously mentioned error, I'm just getting a 403 error from the STS service.
software.amazon.awssdk.services.sts.model.StsException: Access denied (Service: Sts, Status Code: 403 ...
I had this problem too.
However, I can confirm that I can make it work with the latest version of the SDK, in my case version 2.15.26, and with the use of the AnonymousCredentialsProvider like this:
StsClient stsClient = StsClient.builder()
.credentialsProvider(software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider.create())
.build();
Without the use of the AnonymousCredentialsProvider I get :
"SdkClientException: Unable to load credentials from any of the providers in the chain"
I don't think the required use of the AnonymousCredentialsProvider is well-documented, but perhaps I missed something? In fact the Javadoc says this:
Calling AssumeRoleWithSAML does not require the use of AWS security credentials. The identity of the caller is validated by using keys in the metadata document that is uploaded for the SAML provider entity for your identity provider.
This sentence doesn't make it obvious that in fact you _MUST_ use AnonymousCredentialsProvider. You can even use a bogus credentials provider, it just needs to be there and return a non-null AwsCredentials object .. which then won't be used anyway. Weird.
I had similar issue in my code
I followed @lbruun solution and worked.
stsClient = StsClient.builder()
.credentialsProvider(AnonymousCredentialsProvider.create())
.region(region)
.build();
Most helpful comment
I had this problem too.
However, I can confirm that I can make it work with the latest version of the SDK, in my case version
2.15.26, and with the use of theAnonymousCredentialsProviderlike this:Without the use of the
AnonymousCredentialsProviderI get :"SdkClientException: Unable to load credentials from any of the providers in the chain"
I don't think the required use of the
AnonymousCredentialsProvideris well-documented, but perhaps I missed something? In fact the Javadoc says this:This sentence doesn't make it obvious that in fact you _MUST_ use
AnonymousCredentialsProvider. You can even use a bogus credentials provider, it just needs to be there and return a non-nullAwsCredentialsobject .. which then won't be used anyway. Weird.