aws-sdk-js icon indicating copy to clipboard operation
aws-sdk-js copied to clipboard

SSO Credentials Provider fails to load AWS credentials if the AWS IAM Identity Center access token associated with an SSO session has expired or is about to expire

Open sjakthol opened this issue 2 years ago • 3 comments

Describe the bug

When using AWS IAM Identity Center authentication with the sso-session based configuration, the AWS SDK SSO Credential Provider fails to load AWS credentials if the AWS IAM Identity Center access token cached to disk requires a refresh.

Expected Behavior

AWS SDK SSO Credential Provider refreshes the AWS IAM Identity Center access token associated with the SSO session and uses the fresh access token to fetch AWS credentials from AWS IAM Identity Center.

Current Behavior

AWS SDK SSO Credential Provider fails to obtain a fresh AWS IAM Identity Center access token if the previous token requires refresh (has expired or is expiring within next 5 minutes).

Reproduction Steps

  1. Create file called config with following content (fill in your AWS IAM Identity Center details):
[sso-session mysso]
sso_start_url = https://mysso.awsapps.com/start
sso_region = eu-west-1

[profile profile-1]
sso_session = mysso
sso_account_id = 000000000000
sso_role_name = MyRole
  1. Login to AWS IAM Identity Center: aws sso login --session-name mysso
  2. Update the expiresAt field value to a timestamp that is in the past in the token cache file Step 2 created under ~/.aws/sso/cache/ (you can also wait for an hour for the access token on disk to expire)
  3. Create file called index.js with following content:
const AWS = require("aws-sdk");
const sts = new AWS.STS();
(async () => {console.log(await sts.getCallerIdentity().promise())})();
  1. Execute following command:
env AWS_CONFIG_FILE=./config AWS_REGION=eu-west-1 AWS_PROFILE=profile-1 node index.js

This should fail with the following error which indicates SSO Credential Provider failed to resolve credentials and SDK fell through to latter providers in the chain (SSO credential provider errors are not logged):

Error [CredentialsError]: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
    at Timeout.connectTimeout [as _onTimeout] (/sdkbug/node_modules/aws-sdk/lib/http/node.js:69:15)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7) {
  code: 'CredentialsError',
  time: 2023-06-08T04:16:52.349Z,
  retryable: true,
  originalError: {
    message: 'Could not load credentials from any providers',
    code: 'CredentialsError',
    time: 2023-06-08T04:16:52.349Z,
    retryable: true,
    originalError: {
      message: 'EC2 Metadata roleName request returned error',
      code: 'TimeoutError',
      time: 2023-06-08T04:16:52.348Z,
      retryable: true,
      originalError: {
        message: 'Socket timed out without establishing a connection',
        code: 'TimeoutError',
        time: 2023-06-08T04:16:52.347Z,
        retryable: true
      }
    }
  }
}

Possible Solution

Here's the possible cause for this issue.

SsoCredentials.load() calls SsoCredentials.getToken():

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/credentials/sso_credentials.js#L114

SsoCredentials.getToken() creates a new SSOTokenProvider:

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/credentials/sso_credentials.js#L176-L178

SSOTokenProvider constructor invokes SSOTokenProvider.get() to load/refresh the token:

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/token/sso_token_provider.js#L99

Call to get() triggers a call to SSOTokenProvider.load(). This reads the the expired token from disk, notices it has expired and starts to refresh it in the background (async call). load() also sets the lastRefreshAttemptTime to current time:

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/token/sso_token_provider.js#L202

SSOTokenProvider constructor returns as load() made an async call. SsoCredentials.getToken() continues and calls SSOTokenProvider.load() (this is the second call to SSOTokenProvider.load()):

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/credentials/sso_credentials.js#L179-L184

SSOTokenProvider notices that the token on disk is still expired (refresh process is still running in the background). But when it checks the lastRefreshAttemptTime, it seems that a refresh was just started and it triggers the SsoCredentials callback without a valid token:

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/token/sso_token_provider.js#L180-L184

SsoCredentials.getToken() assumes a token is now available and returns that to SsoCredentials.load():

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/credentials/sso_credentials.js#L183

However, since the refresh had not yet completed, ssoTokenProvider.token is undefined and SsoCredentials.load() is unable to fetch AWS credentials with it.

Because of this AWS SDK discards the SsoCredentials provider and moves forward to try other providers in the chain. During this time the initial AWS IAM Identity Center access token refresh might complete and a fresh access token might be written to disk. So the next time SsoCredentials provider tries to load AWS credentials, it might find a valid token from disk and the provider is able to fetch AWS credentials from AWS IAM Identity Center.

If I'm reading the code correctly, SsoCredentials.getToken() should call the SSOTokenProvider.get() instead of SSOTokenProvider.load(). The get method seems to fold multiple token load attempts into one load as per logic in:

https://github.com/aws/aws-sdk-js/blob/cae1321d3b665dbf3f9844a03bc198a7675b0e68/lib/token.js#L175

Additional Information/Context

No response

SDK version used

2.1393.0

Environment details (OS name and version, etc.)

sjakthol avatar Jun 08 '23 04:06 sjakthol

Just to confirm that any fix for these issues will also fix the issue where it seems aws-cdk doesn't engage the token refreshing at all? Because https://github.com/aws/aws-cdk/issues/24782 has been said to be tracked by the changes on ☝️. And so I hope that carries over to this too!

spoco2 avatar Jul 24 '23 23:07 spoco2

It's not entirely clear if this is the issue that causes the CDK issue you linked to. Currently CDK uses both SDK v2 and v3 internally and I'm not sure which SDK is used for the credential resolution over there.

However, it's very likely that the CDK problem is caused by either this or https://github.com/aws/aws-sdk-js-v3/issues/4798 depending on which SDK version is used there. I guess we'll see that when fix to this and https://github.com/aws/aws-sdk-js-v3/issues/4798 is merged and released, and CDK is updated to take newer version of SDKs into use.

sjakthol avatar Jul 26 '23 14:07 sjakthol

I'm still trying actions in maticnetwork/polygon-edge but nightly build #76 run fails in https://github.com/Ishmaello/polygo-edge/actions/runs/5779793298/job/15662572723 with response "Run aws-actions/configure-aws-credentials@v2 with: audience: sts.amazonaws.com Error: Input required and not supplied: aws-region (node:1703) NOTE: We are formalizing our plans to enter AWS SDK for JavaScript (v2) into maintenance mode in 2023.

Please migrate your code to use AWS SDK for JavaScript (v3). For more information, check the migration guide at https://a.co/7PzMCcy (Use node --trace-warnings ... to show where the warning was created"

Ishmaello avatar Aug 07 '23 21:08 Ishmaello

I believe this is also related, see: https://github.com/aws/aws-cdk/issues/27265#issuecomment-1742139875

@marcusirgens found that removing the sso_session from his ~/.aws/config file fixed his issues. I was able to verify that removing sso_session also fixed my cdk cli issues.

Here is a diff I made which triggers the bug. The inclusion of sso_session does not break using the aws cli, or boto3 session using the same sso profile I've configured. just cdk, which uses aws-sdk-js.

https://github.com/aws/aws-sdk-js/compare/master...rangerthegood:aws-sdk-js:sso_bug

rangerthegood avatar Oct 23 '23 04:10 rangerthegood

Hi, what's holding back this issue's PR from getting merged?

My team has to log in every hour despite my session length being 12 hours. This is quite frustrating

arturenault avatar Apr 10 '24 21:04 arturenault

Hi, could you get this issue's PR in? We are also being affected by this issue and having to log in every hour is a pain.

kstromeiraos avatar Apr 29 '24 15:04 kstromeiraos

+1 ^

ConnorHeggie avatar Apr 30 '24 16:04 ConnorHeggie

I hope my aws account has been deleted I'll start afresh

Ishmaello avatar May 19 '24 22:05 Ishmaello