-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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 #4441
Comments
… refresh This commit fixes an issue which caused the SSO credentials provider to fail to resolve credentials if a cached access token associated with an sso-session required a refresh. Reason for the issue is that SSOTokenProvider.load() skips token refresh if another refresh had been kicked off within the last 30 seconds. In this case, SSOTokenProvider.load() was called twice when credentials were being resolved: once from SSOTokenProvider constructor and second time from SsoCredentials.getToken() method. If the access token on disk had expired, the first call to SSOTokenProvider.load() from SSOTokenProvider constructor would kick off async token refresh process. However, if this had not completed before the second call to SSOTokenProvider.load() from SsoCredentials.getToken() was made, SSOTokenProvider.load() would call the SsoCredentials.getToken() callback without a valid token. Because of this, SsoCredentials did not have a valid SSO access token available to fetch AWS credentials and credential resolution failed. Loading the SSO access token with SSOTokenProvider.get() instead of SSOTokenProvider.load() fixes the issue as SSOTokenProvider.get() tracks the calls to .get(), triggers the load just once and invokes all the callbacks when the new token is available. Fixes aws#4441
… refresh This commit fixes an issue which caused the SSO credentials provider to fail to resolve credentials if a cached access token associated with an sso-session required a refresh. Reason for the issue is that SSOTokenProvider.load() skips token refresh if another refresh had been kicked off within the last 30 seconds. In this case, SSOTokenProvider.load() was called twice when credentials were being resolved: once from SSOTokenProvider constructor and second time from SsoCredentials.getToken() method. If the access token on disk had expired, the first call to SSOTokenProvider.load() from SSOTokenProvider constructor would kick off async token refresh process. However, if this had not completed before the second call to SSOTokenProvider.load() from SsoCredentials.getToken() was made, SSOTokenProvider.load() would call the SsoCredentials.getToken() callback without a valid token. Because of this, SsoCredentials did not have a valid SSO access token available to fetch AWS credentials and credential resolution failed. Loading the SSO access token with SSOTokenProvider.get() instead of SSOTokenProvider.load() fixes the issue as SSOTokenProvider.get() tracks the calls to .get(), triggers the load just once and invokes all the callbacks when the new token is available. Fixes aws#4441
…requires a refresh This commit fixes an issue which caused the SSO credentials provider to fail to resolve credentials if a cached access token associated with an sso-session required a refresh. Reason for the issue is that SSOTokenProvider.load() skips token refresh if another refresh had been kicked off within the last 30 seconds. In this case, SSOTokenProvider.load() was called twice when credentials were being resolved: once from SSOTokenProvider constructor (via .get()) and second time from SsoCredentials.getToken() method. If the access token on disk had expired, the first call to SSOTokenProvider.load() from SSOTokenProvider constructor kicked off a token refresh. When SsoCredentials.getToken() called SSOTokenProvider.load() again immediately, SSOTokenProvider would skip the token refresh and invoke the SsoCredentials.getToken() callback without having a valid token. Because of this, SsoCredentials did not get a valid SSO access token from SSOTokenProvider and it could not fetch AWS credential from AWS IAM Identity Center. Loading the SSO access token with SSOTokenProvider.get() instead of SSOTokenProvider.load() fixes the issue as SSOTokenProvider.get() tracks the calls to .get(), triggers the load just once and invokes all the callbacks when the new token is available. This way SsoCredentials.getToken() will receive a valid access token once the initial load kicked off by the SSOTokenProvider constructor completes and SsoCredentials can use the refreshed token to fetch AWS credentials from AWS IAM Identity Center. Fixes aws#4441
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 aws/aws-cdk#24782 has been said to be tracked by the changes on ☝️. And so I hope that carries over to this too! |
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 aws/aws-sdk-js-v3#4798 depending on which SDK version is used there. I guess we'll see that when fix to this and aws/aws-sdk-js-v3#4798 is merged and released, and CDK is updated to take newer version of SDKs into use. |
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 Please migrate your code to use AWS SDK for JavaScript (v3). |
I believe this is also related, see: aws/aws-cdk#27265 (comment) @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. |
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 |
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. |
+1 ^ |
I hope my aws account has been deleted I'll start afresh |
…requires a refresh (#4443) This commit fixes an issue which caused the SSO credentials provider to fail to resolve credentials if a cached access token associated with an sso-session required a refresh. Reason for the issue is that SSOTokenProvider.load() skips token refresh if another refresh had been kicked off within the last 30 seconds. In this case, SSOTokenProvider.load() was called twice when credentials were being resolved: once from SSOTokenProvider constructor (via .get()) and second time from SsoCredentials.getToken() method. If the access token on disk had expired, the first call to SSOTokenProvider.load() from SSOTokenProvider constructor kicked off a token refresh. When SsoCredentials.getToken() called SSOTokenProvider.load() again immediately, SSOTokenProvider would skip the token refresh and invoke the SsoCredentials.getToken() callback without having a valid token. Because of this, SsoCredentials did not get a valid SSO access token from SSOTokenProvider and it could not fetch AWS credential from AWS IAM Identity Center. Loading the SSO access token with SSOTokenProvider.get() instead of SSOTokenProvider.load() fixes the issue as SSOTokenProvider.get() tracks the calls to .get(), triggers the load just once and invokes all the callbacks when the new token is available. This way SsoCredentials.getToken() will receive a valid access token once the initial load kicked off by the SSOTokenProvider constructor completes and SsoCredentials can use the refreshed token to fetch AWS credentials from AWS IAM Identity Center. Fixes #4441
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
config
with following content (fill in your AWS IAM Identity Center details):aws sso login --session-name mysso
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)index.js
with following content: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):
Possible Solution
Here's the possible cause for this issue.
SsoCredentials.load()
callsSsoCredentials.getToken()
:aws-sdk-js/lib/credentials/sso_credentials.js
Line 114 in cae1321
SsoCredentials.getToken()
creates a newSSOTokenProvider
:aws-sdk-js/lib/credentials/sso_credentials.js
Lines 176 to 178 in cae1321
SSOTokenProvider
constructor invokesSSOTokenProvider.get()
to load/refresh the token:aws-sdk-js/lib/token/sso_token_provider.js
Line 99 in cae1321
Call to
get()
triggers a call toSSOTokenProvider.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 thelastRefreshAttemptTime
to current time:aws-sdk-js/lib/token/sso_token_provider.js
Line 202 in cae1321
SSOTokenProvider
constructor returns asload()
made an async call.SsoCredentials.getToken()
continues and callsSSOTokenProvider.load()
(this is the second call toSSOTokenProvider.load()
):aws-sdk-js/lib/credentials/sso_credentials.js
Lines 179 to 184 in cae1321
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 theSsoCredentials
callback without a valid token:aws-sdk-js/lib/token/sso_token_provider.js
Lines 180 to 184 in cae1321
SsoCredentials.getToken()
assumes a token is now available and returns that toSsoCredentials.load()
:aws-sdk-js/lib/credentials/sso_credentials.js
Line 183 in cae1321
However, since the refresh had not yet completed,
ssoTokenProvider.token
isundefined
andSsoCredentials.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 theSSOTokenProvider.get()
instead ofSSOTokenProvider.load()
. The get method seems to fold multiple token load attempts into one load as per logic in:aws-sdk-js/lib/token.js
Line 175 in cae1321
Additional Information/Context
No response
SDK version used
2.1393.0
Environment details (OS name and version, etc.)
The text was updated successfully, but these errors were encountered: