Saturday, August 13, 2022

Assume AWS role and retrieve temporary credentials to access allowed services of AWS

 Scenario

Suppose I am an user of an AWS account with account id 1111 and I want to programmatically access a S3 bucket created in another AWS account 2222. So, how can I access it programmatically through cross account. To fulfill this scenario, we have to follow the following steps:

Steps:

  1. Admin of account 2222 should create a bucket say Bucket2222.
  2. Admin of account 2222 should create an IAM Role with minimum 2 policies. One will be the Trust Policy and second with the list of accesses of the Bucket2222
  3. Admin of account 1111 should give me the IAM access of Assume Role
  4. In Node JS code, I have to first get the temporary credential of the IAM Role created in Account 2222 by using aws-sdk version 3 STSClient class
  5. If needed I can cache the credential in API side to reuse it until it is expired
  6. I will access the Bucket2222 in Account 2222 by using S3Client class of aws-sdk version 3 by passing the temporary credentials
Below is the complete code to access the temporary credential of this role and then listing the bucket items:

Package.json

{
  "name": "aws_node_poc",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Jitendra Kumar Singh",
  "license": "ISC",
  "dependencies": {
    "@aws-sdk/client-s3": "^3.142.0",
    "@aws-sdk/client-sts": "^3.142.0"
  }
}


Constants.js

module.exports = {
    "REGION": "My Region name",
    "ASSUME_ROLE_ARN": "arn:aws:iam::2222:role/my_assume_role_name",
    "TEST_BUCKET_NAME": "Bucket2222"
}

AssumeRoleAndAccessBucket.js


 const { S3Client, ListObjectsCommand } = require("@aws-sdk/client-s3");
 const { STSClient, AssumeRoleCommand, GetCallerIdentityCommand } = require("@aws-sdk/client-sts");
 const { REGION, ASSUME_ROLE_ARN, TEST_BUCKET_NAME } = require('../../util/constants.js');

 //Getting Role credentials
 const assumeRole = async () => {
    try {
        let rolecreds;
        /**
         * The credential can be cached on api side in reddish or memcache
         * to reuse the credential till it is expired. This credential is having Expiration
         * attribute that defines the time when it is expired
         * We can check this time to verify whether temp credential is expired
         * If not then reuse it and if expired then send a hit to AWS to get new temp credential
         */
        //rolecreds = "Get credential from API cache if cached and if not expired"

        if(!rolecreds) {
            // Create an Amazon STS service client object.
            const stsClient  = new STSClient({
                region: REGION
            });

            // Set the parameters
            const params = {
                RoleArn: ASSUME_ROLE_ARN, //ARN_OF_ROLE_TO_ASSUME
                RoleSessionName: "MyAssueRoleSessionName",
                DurationSeconds: 3600,
            };

            //Assume Role
            const data = await stsClient.send(new AssumeRoleCommand(params));
            console.log("Cred = ", data);
           
            rolecreds = {
                accessKeyId: data.Credentials.AccessKeyId,
                secretAccessKey: data.Credentials.SecretAccessKey,
                sessionToken: data.Credentials.SessionToken
            };
        }        

        /*const stsParams = { credentials: rolecreds };
        const stsClient1 = new STSClient(stsParams);
        const results = await stsClient1.send(
            new GetCallerIdentityCommand(rolecreds)
        );*/

        return rolecreds;
    } catch (error) {
        throw error;  
    }    
 }

 //Getting Object List from Bucket
 const listObjects = async(roleCred) => {
    try {
        //Creating S3 Client
        const s3Client = new S3Client({
            region: REGION,
            credentials: roleCred
        });
        //Getting object list from bucket
        const bucketParams = { Bucket: TEST_BUCKET_NAME };
        const data = await s3Client.send(new ListObjectsCommand(bucketParams));
        return data;
    } catch (error) {
        throw error;
    }
 }

 //Getting Role credential and calling function to get object list from bucket
 const listBucketObjects = async() => {
    try {
        const roleCred = await assumeRole();
        //get object list of the bucket
        const result = await listObjects(roleCred);
        return result;
    } catch (error) {
        throw error;
    }    
 }

 //Triggering function to initiate process of getting data from bucket by using Role
 listBucketObjects()
 .then(data => {
    console.log(data);
 }).catch(err => {
    console.log("Error in my code = ", err);
 })
 

This is all I am having here to deal with such scenarios. Please let me know in comment section if you facing any problem in any other scenarios, I will try to post blog related with those issues.