Skip to content

SDK Credential Provider in v3 errors out #7310

@nagmesh

Description

@nagmesh

Pre-Migration Checklist

Which JavaScript Runtime is this issue in?

Node.js (includes AWS Lambda)

AWS Lambda Usage

  • Yes, my application is running on AWS Lambda.
  • No, my application is not running on AWS Lambda.

Describe the Migration Issue

The solution I'm working on gets credential with assume role and provides accessKey, session token, secret key. When a similar account comes to get credentials it checks the cache and takes credentials if its there or adds credentials to it.

With SDK V3 we are testing to use @aws-sdk/credential-providers. When a test is run across 5 accounts and 3 regions everything looks fine. However, when a test is run with 250 accounts across 10 regions it throws an error ECONNREFUSED.

Current code snippet

New code

Code Comparison

Current code snippet

New code:

async function sdkCredentials(
  command: string,
  partition: string,
  stage: string,
  configDirPath?: string,
  accountId?: string,
  region?: string,
): Promise<SDKv3CompatibleCredentialProvider> {
  const currentAccount = await getCurrentAccountId(partition, getGlobalRegion(partition));

  // If we're already in the target account, use environment credentials
  if (currentAccount === accountId || !accountId) {
    logger.debug(`Using environment credentials for current account ${accountId}`);
    return fromNodeProviderChain();
  }

  // Otherwise, we need cross-account credentials
  return crossAccountCredentails(command, partition, stage, configDirPath, accountId, region);
}
function crossAccountCredentails(
  command: string,
  partition: string,
  stage: string,
  configDirPath?: string,
  accountId?: string,
  region?: string,
) {
  const assumeRoleName = setPluginAssumeRoleName(command, configDirPath, stage);

  if (!assumeRoleName) {
    throw new Error('Assume role name is required for credential configuration');
  }

  if (!accountId) {
    throw new Error('Account ID is required for credential configuration');
  }

  // External pipeline scenario - chain through management account
  if (
    process.env['MANAGEMENT_ACCOUNT_ID'] &&
    process.env['MANAGEMENT_ACCOUNT_ROLE_NAME'] &&
    accountId! !== process.env['MANAGEMENT_ACCOUNT_ID']!
  ) {
    logger.debug(
      `Using chained credentials: Management Account ${process.env['MANAGEMENT_ACCOUNT_ID']} -> Target Account ${accountId} with role ${assumeRoleName}`,
    );
    return fromTemporaryCredentials({
      params: {
        RoleArn: `arn:${partition}:iam::${accountId}:role/${assumeRoleName}`,
        RoleSessionName: 'cdk-toolkit-session',
      },
      masterCredentials: fromTemporaryCredentials({
        params: {
          RoleArn: `arn:${partition}:iam::${process.env['MANAGEMENT_ACCOUNT_ID']}:role/${process.env['MANAGEMENT_ACCOUNT_ROLE_NAME']}`,
          RoleSessionName: 'lza-external-pipeline-session',
        },
      }),
      clientConfig: { retryStrategy: setRetryStrategy(), region: region ?? getGlobalRegion(partition) },
    });
  } else if (
    process.env['MANAGEMENT_ACCOUNT_ID'] &&
    process.env['MANAGEMENT_ACCOUNT_ROLE_NAME'] &&
    accountId! === process.env['MANAGEMENT_ACCOUNT_ID']!
  ) {
    logger.debug(
      `Using environment credentials for account ${accountId} with role ${process.env['MANAGEMENT_ACCOUNT_ROLE_NAME']}`,
    );
    return fromTemporaryCredentials({
      params: {
        RoleArn: `arn:${partition}:iam::${process.env['MANAGEMENT_ACCOUNT_ID']}:role/${process.env['MANAGEMENT_ACCOUNT_ROLE_NAME']}`,
        RoleSessionName: 'lza-external-pipeline-session',
      },
      clientConfig: { retryStrategy: setRetryStrategy(), region: region ?? getGlobalRegion(partition) },
    });
  }

  // Direct assume role to target account
  logger.debug(`Using assume role credentials for account ${accountId} with role ${assumeRoleName}`);
  return fromTemporaryCredentials({
    params: {
      RoleArn: `arn:${partition}:iam::${accountId}:role/${assumeRoleName}`,
      RoleSessionName: 'cdk-toolkit-session',
    },
    clientConfig: { retryStrategy: setRetryStrategy(), region: region ?? getGlobalRegion(partition) },
  });
}
export function setRetryStrategy() {
  const numberOfRetries = Number(process.env['ACCELERATOR_SDK_MAX_ATTEMPTS'] ?? 800);
  return new ConfiguredRetryStrategy(numberOfRetries, (attempt: number) => 100 + attempt * 1000);
}

Typical run of these command is something like

for (const region of enabledRegions) {
      for (const account of nonManagementAccounts) {
        const accountId = accountsConfig.getAccountId(account.name);
        logger.info(`Executing ${toolkitProps.stage} for ${account.name} account in ${region} region.`);
        promises.push(
          AcceleratorToolkit.execute({
            accountId,
            region,
            ...toolkitProps,
          }),
        );
        if (promises.length >= maxStacks) {
          await Promise.all(promises);
          promises.length = 0;
        }
      }

Observed Differences/Errors

Older sdkv2 code works and fails sometimes with security token expired (non-standard partitions) intermittently. Retry normally works.

New code fails with

Cannot assume role for 3600 seconds: Error: getaddrinfo ENOTFOUND sts.us-west-2.amazonaws.com
Assuming role arn:aws:iam::xx:role/AWSControlTowerExecution for 3600 seconds
2025-09-02 19:10:25.405 | error | toolkit | Deployment of AWSAccelerator-ResourcePolicyEnforcementStack-xx-us-west-2 failed: connect ECONNREFUSED 52.94.177.163:443
Could not assume role in target account using current credentials (which are for account xx) connect ECONNREFUSED 44.248.100.60:443 .

Additional Context

I would prefer if we can use native sdkv3 credential helper and deprecate those packages.

Metadata

Metadata

Assignees

Labels

closed-for-stalenessp2This is a standard priority issueresponse-requestedWaiting on additional info and feedback. Will move to \"closing-soon\" in 7 days.v2-v3-inconsistencyBehavior has changed from v2 to v3, or feature is missing altogether

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions