'AWS Java SDK not finding profile when using AWS SSO

I can't reach aws when my login is made using AWS SSO. I login from my computer using:

aws sso login --profile staging

The profile is configured like this:

[profile staging]
sso_start_url = https://som-nice-working-url
sso_region = us-east-1
sso_account_id = 1234
sso_role_name = the-role-name
region = eu-west-1
output = yaml

After doing the login I can access aws through aws cli.

Then I set the varible: AWS_PROFILE=staging But on java I'm getting the following exception:

com.amazonaws.SdkClientException: Unable to load AWS credentials from any provider in the chain: [EnvironmentVariableCredentialsProvider: Unable to load AWS credentials from environment 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: You must specify a value for roleArn and roleSessionName, com.amazonaws.auth.profile.ProfileCredentialsProvider@369a95a5: No AWS profile named 'staging', com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper@6d6f6ca9: Failed to connect to service endpoint: ]

I have tryed using the ProfileCredentialsProvider with "staging" but the result is the same.

What CredentialsProvider should I use?

My code is using the DefaultProviderChain:

AWSGlueClient.builder()
            .withRegion("eu-west-1")
            .build()

Thank you.



Solution 1:[1]

For a Java application you'll need the SSO Dependency.

As of writing the latest is version 2.16.76

// Gradle example
dependencies {
    
    implementation(platform("software.amazon.awssdk:bom:2.16.70"))
    implementation("software.amazon.awssdk:sso:2.16.76")
}

You'll also need to set a default profile in either ~/.aws/configuration or ~/.aws/credentials

More info below:

https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials.html https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-credentials https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-additional.html#setup-additional-credentials

But, you should also be able to just set the AWS_PROFILE environment variable to your profile and it should just magically work without the SSO dependency.

In your example, specifically:

AWS_PROFILE=staging

Solution 2:[2]

In my case, just adding the aws-sso dependency:

    <dependency>
       <groupId>software.amazon.awssdk</groupId>
       <artifactId>sso</artifactId>
    </dependency>

allows the default credentials providers chain to pick up sso under ProfileCredentialsProvider: Profile credentials provider with sso profile

To work out of the box, it requires from you to have the [default] profile specified. Otherwise, simply using .credentialsProvider(ProfileCredentialsProvider.create("xyz")) also works with [profile xyz].

If all fails, add the credentials provider manually:

  1. Setup your profile file .aws/config
  2. Login with cli aws sso login --profile <your_profile>
  3. A json file is generated in .aws/sso/cache with contents as described here
{
 "startUrl": "https://my-sso-portal.awsapps.com/start",
 "region": "us-east-1",
 "accessToken": "eyJlbmMiOiJBM….",
 "expiresAt": "2020-06-17T10:02:08UTC"
}
  1. Include in your project a dependency to software.amazon.awssdk:sso
  2. Create SsoCredentialsProvider with the data from json file:
CredentialsProvider ssoCredentialsProvider = ((SsoCredentialsProvider.Builder) SsoCredentialsProvider.builder())
.ssoClient(SsoClient.builder().region(<REGION_FROM_JSON>).build())
.refreshRequest( () ->
    GetRoleCredentialsRequest.builder()
      .roleName("<ROLE_FROM_PROFILE>")
      .accountId("<ACCOUNT_ID_FROM_PROFILE>")
      .accessToken("<ACCESS_TOKEN_FROM_JSON>")
      .build()
).build();

Solution 3:[3]

I might be wrong, however IMO there is no way to use AWS SSO within AWS SDK yet based on https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/credentials.html.

AFAIK AWS SSO is at the moment integrated only into AWS CLI - https://docs.aws.amazon.com/singlesignon/latest/userguide/integrating-aws-cli.html

Solution 4:[4]

Support for SSO Credentials Provider was added to AWS SDK for Java V2 in version 2.15.33 (November 2020). Older versions of the SDK don't work with SSO. (See the Feature Request & the PR)

If you are using maven, make sure the versions of all SDK modules are compatible by specifying the version in the dependencyManagement section as described in the documentation. e.g.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.17.8</version>  <!--Must be 2.15.33 or higher-->
            <type>pom</type>
            <scope>import</scope>
       </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>dynamodb</artifactId>
    </dependency>
    <dependency>
       <groupId>software.amazon.awssdk</groupId>
       <artifactId>sso</artifactId>
    </dependency>
</dependencies>

Solution 5:[5]

Waiting for SDK 2 to integrate SSO, aws-sso-cred-restore is a workaround:

Intall it (with Python 3):

pip3 install aws-sso-cred-restore

Then you can run this (it get a Token available for around 1h, so you should run it every hour to refresh):

aws-sso-cred-restore --profile $YOUR_PROFILE

And you can use again your $YOUR_PROFILE in your Java app.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Milan Gatyas
Solution 4
Solution 5 tdebroc