AWS JavaScript SDK v3 STSClient AssumeRoleCommand fails, but v2 STS assumeRole works

0

With the v2 SDK, I can assume a role and get temporary credentials for an S3 client using the following code (wrapped in an async function, error handling removed for brevity): EDIT: Original sample code appears further down. Here is the most simplified version I can create, which shows both v2 and v3 examples, where the v2 example works, and the v3 example fails with AccessDenied. New Example:

const STS = require("aws-sdk/clients/sts"); // v2
const { AssumeRoleCommand, STSClient } = require("@aws-sdk/client-sts"); // v3

process.env.AWS_ACCESS_KEY_ID="<my account 1 aws access key id>";
process.env.AWS_SECRET_ACCESS_KEY="<my account 1 aws secret access key>";
const region = "us-east-1";
const RoleArn = "arn:aws:iam::<account 2>:role/<role>";

async function v2example() {
  const stsClient = new STS({
    region
  });

  const command = {
    RoleArn,
    RoleSessionName: 'sessionV2'
  };

  const assumeRoleResponse = await stsClient.assumeRole(command).promise();
  console.log(assumeRoleResponse);
}

async function v3example() {
  const stsClient = new STSClient({
    region
  });
  
  const command = new AssumeRoleCommand({
    RoleArn,
    RoleSessionName: 'sessionV3'
  });

  const assumeRoleResponse = await stsClient.send(command);
  console.log(assumeRoleResponse);
}

v2example(); // success
v3example(); // AccessDenied

Original Example:

const region = "us-east-1";
const RoleArn = "<My_Role_Arn_With_S3_Permissions>";

// Get the user or system credentials from default provider chain
// (env, sso credentials, ini files, ECS, process, Token File Web ID, or EC2 Metadata)
const chain = new AWS.CredentialProviderChain();
const credentials = await chain.resolvePromise();
AWS.config.credentials = credentials;

// Create STS client using the default credentials
const stsClient = new STS({
  credentials,
  region
});

// Assume a different role and get temp credentials for S3 access
const roleToAssume = {
  RoleArn,
  RoleSessionName: 'session1',
  Duration: 900
};
const roleData = await stsClient.assumeRole(roleToAssume).promise();
const tempCredentials = stsClient.credentialsFrom(roleData, new AWS.TemporaryCredentials(roleToAssume));

// Create S3 client using the temporary credentials
const s3Client = new S3({
  credentials: tempCredentials,
  region,
  signatureVersion: 'v4'
});

However, the following code, which I think is roughly the equivalent for v3 (up to assuming the role... I'm stuck there), gives an error "AccessDenied: User: <my user Arn> is not authorized to perform: sts:AssumeRole on resource: <RoleArn>". But I know from the working v2 code that my user is authorized to perform sts:AssumeRole, so what could the problem be?

const region = "us-east-1";
const RoleArn = "<My_Role_Arn_With_S3_Permissions>";

// Get the user or system credentials from default provider chain
// (env, sso credentials, ini files, ECS, process, Token File Web ID, or EC2 Metadata)
const credentials = fromNodeProviderChain();

// Create STS client using the default credentials
const stsClient = new STSClient({
  credentials,
  region
});

// Assume a different role and get temp credentials for S3 access
const roleToAssume = {
  RoleArn,
  RoleSessionName: 'session1',
  Duration: 900
};
const roleCommand = new AssumeRoleCommand(roleToAssume);
const assumeRoleResponse = await stsClient.send(roleCommand);

Any suggestions? This is preventing me from being able to move from the v2 SDK to the v3 SDK. Thanks.

EDIT: My user is a member of a group which has the policy that grants the STS AssumeRole action. Is there anything I need to do with regards to that group information when creating the STSClient? Also, do I need to explicitly disable MFA for my user in order for this to work? I'm just wondering if there's some difference between v2 and v3 with regards to how MFA or group membership info is recognized?

2 Answers
0
AWS
niris
answered 6 months ago
  • Unfortunately, I've already reviewed that and it's essentially what I'm already doing.

0

The issue you are having may be caused because with V2 you are allowed to provide credentials details directly as parameters to the client, but with V3 you need to specify those details as a credentials object.

For example, with v2 you are able to do the following:

const client = new SQSClient({
    accessKeyId: 'ACCESSKEYID',
    secretAccessKey: 'SECRETACCESSKEY',
    sessionToken: 'SESSION-TOKEN',
    expiration: 'EXPIRATION'
})

But with v3 you need do the following:

const sqsClient = new SQSClient({
        region: 'us-west-2',
        credentials: {
              accessKeyId: 'ACCESSKEYID',
              secretAccessKey: 'SECRETACCESSKEY',
              sessionToken: 'SESSION-TOKEN',
               expiration: 'EXPIRATION'
        }
    });

Please check if you are able making the above changes.

Also please refer below documentation about using MFA with AssumeRole.

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-athena/classes/assumerolecommand.html

Also, you can check in below documentation which state MFA Serial code is required if params has SerialNumber config.

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_credential_providers.html#fromtemporarycredentials

The below document captures notable changes from AWS SDK for JavaScript v2 to v3 : https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/migrating/notable-changes/

AWS
answered 6 months ago
  • This is not the issue, as you can see from my examples above that I'm explicitly passing a credentials property.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions