aws / aws-sdk-js

AWS SDK for JavaScript in the browser and Node.js
https://aws.amazon.com/developer/language/javascript/
Apache License 2.0
7.57k stars 1.55k forks source link

Issues with SSO-based source_profile #4301

Open gilesvessey opened 1 year ago

gilesvessey commented 1 year ago

Describe the bug

I have a somewhat complex IAM assume-role configuration that should work using the SDK and does work using the CLI.

[profile mysso]
sso_start_url = ...
sso_region = us-east-1
sso_account_name = ...
sso_account_id = ...
sso_role_name = ...
region = us-east-1
credential_process = aws-sso-util credential-process --profile ...
sso_auto_populated = true 
[profile usesmysso]
source_profile = mysso
role_arn = arn:aws:iam::...:role/i-want-to-be-this-role
external_id = ...
region = us-east-1

Expected Behavior

THE ONLY AWS_ ENVIRONMENT VARIABLE SET IS AWS_SDK_LOAD_CONFIG=1

gvessey@lap-gvessey  ➤  env | grep AWS
AWS_SDK_LOAD_CONFIG=1

This works great:

aws sts get-caller-identity --profile usesmysso

Therefore, using the AWS SDK, the following should work as well:

    const aws = require('aws-sdk')
    const opts = { region: 'us-east-1', credentials: new aws.SharedIniFileCredentials({ profile: 'usesmysso' }), }
    const sts = new aws.STS(opts)
    return sts.getCallerIdentity({}).promise()

Current Behavior

CLI OUTPUT (working):

{
    "UserId": "AROAVIZUEM43GSDSGGNMO:botocore-session-1671218894",
    "Account": "[REDACTED]",
    "Arn": "arn:aws:sts::[REDACTED]:assumed-role/[REDACTED]/botocore-session-1671218894"
}

SDK OUTPUT (issues):

Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
Error [CredentialsError]: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
    at SharedIniFileCredentials.load (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/credentials/shared_ini_file_credentials.js:146:11)
    at SharedIniFileCredentials.coalesceRefresh (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/credentials.js:205:12)
    at SharedIniFileCredentials.refresh (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/credentials/shared_ini_file_credentials.js:170:10)
    at SharedIniFileCredentials.get (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/credentials.js:122:12)
    at getAsyncCredentials (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/config.js:408:24)
    at Config.getCredentials (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/config.js:428:9)
    at Request.VALIDATE_CREDENTIALS (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/event_listeners.js:111:28)
    at Request.callListeners (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/sequential_executor.js:102:18)
    at Request.emit (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/Users/gvessey/src/devops/docker/patch-driver/node_modules/aws-sdk/lib/request.js:686:14) {
  code: 'CredentialsError',
  time: 2022-12-16T19:29:51.624Z,
  originalError: {
    message: 'Could not load credentials from SharedIniFileCredentials',
    code: 'CredentialsError',
    time: 2022-12-16T19:29:51.624Z,
    originalError: {
      message: 'Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1',
      code: 'CredentialsError',
      time: 2022-12-16T19:29:51.619Z,
      originalError: [Object]
    }
  }
}

Reproduction Steps

  1. Create a SSO based AWS profile in ~/.aws/config
  2. Create another profile that has the above profile in source_profile, as well as role_arn set to the IAM role you want to use the SSO profile to assume
  3. unset all aws environment variables
  4. export AWS_SDK_LOAD_CONFIG=1
  5. aws sts get-caller-identity --profile << the profile you made in step 2 >>
  6. Note success
  7. Execute the following code
    const aws = require('aws-sdk')
    const opts = { region: 'us-east-1', credentials: new aws.SharedIniFileCredentials({ profile: 'usesmysso' }), }
    const sts = new aws.STS(opts)
    sts.getCallerIdentity({}).promise() 
  8. Note failure

Possible Solution

No response

Additional Information/Context

No response

SDK version used

2.1276.0

Environment details (OS name and version, etc.)

MacOS Catalina 10.15.6, AWS CLI 2.6.2, Node 16.17.1

matan129 commented 1 year ago

Any updates?

gilesvessey commented 1 year ago

Any updates?

None from my end. I managed to get around this in a bit of a painful way - I used the sdk to sts.assumeRole() from the SSO based profile, then took the temporary credentials returned and wrote those to a new profile in ~/.aws/config.

If only there was a way for this to be handled automatically ;)

matan129 commented 1 year ago

So I was actually able to work around this for now using aws2-wrap (here).

This is the setup in ~/.aws/config:

[profile sso]
sso_start_url = https://...
sso_region = us-east-1
sso_account_id = ...
sso_role_name = ... [sso role]
role_session_name = ...

[profile main]
source_profile = sso
role_arn = ... [a role the the SSO role has permissions to assume]
role_session_name = ...

[profile main-wrapped]
credential_process = aws2-wrap --process --profile main

Then, when working with my node app, I set AWS_PROFILE=main-wrapped and AWS_SDK_LOAD_CONFIG=1 env vars.

The credential_process thing is just a simple application that spews out the correct AWS credentials (access key ID, secret, and session token) after assuming the main profile.

richid commented 1 year ago

I just ran into this as well. From what I can gather, the current SSO code (v2.1330.0) does not support using the source_profile attribute to delegate SSO configuration to another profile.

Here is the relevant ~/.aws/config:

[default]
sso_start_url = https://acme.awsapps.com/start
sso_region = us-east-1
sso_account_id = 987654321
sso_role_name = MyPrincipal
region = us-east-1
output = json

[profile sandbox]
role_arn = arn:aws:iam::123456789:role/MyRole
source_profile = default

In my testing I would be dropped into the following error block, as there are no sso_* attributes defined on my sandbox profile:

      } else {
        if (!profile.sso_start_url || !profile.sso_account_id || !profile.sso_region || !profile.sso_role_name) {
          throw AWS.util.error(
            new Error('Profile ' + this.profile + ' does not have valid SSO credentials. Required parameters "sso_account_id", "sso_region", ' +
            '"sso_role_name", "sso_start_url". Reference: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html'),
            { code: self.errorCode }
          );
        }
      }

This does work with aws-cli:

$ aws --profile sandbox sts get-caller-identity | jq -r '.UserId[0:6]'
AROAY7
RanVaknin commented 3 months ago

Hi there,

Thank you for bringing this to our attention through your internal ticket. I have assigned it to our development queue.

All the best, Ran~

novito commented 1 month ago

@RanVaknin any updates on this, OR a workaround that your team suggests?