Search code examples
amazon-web-servicesamazon-dynamodbmulti-tenant

How to allow a Tenant lambda function to query a dynamo table in Control Tower ROOT using NodeJs SDK?


I have a Lambda Function running in a Tenant account that needs to query a DynamoDb Table B inside the Tenant and then query a DynamoDb Table A inside ROOT. This is the code I have so far:

'use strict';

const AWS = require('aws-sdk');
const ddbDc = new AWS.DynamoDB.DocumentClient()


module.exports.testDynamo = async event => {
  try {
    let result 
    let params = {}
    
    // Query Table B inside tenant
    params = {
      TableName: 'Table_B',
      Key: { externalKey : 'CA6E03C' }
    }
    result = await ddbDc.get(params).promise()
    console.log('🚀 result - ', result)  

    // Query Table A inside ROOT
    // Restart ddbDc CLIENT with ROOT credentials ?
    params = {
      TableName: 'Table_A',
      Key: { externalKey : 'MAP_CA6E03C' }
    }
    result = await ddbDc.get(params).promise()
    console.log('🚀 result - ', result)



    return {
      statusCode: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': true
      },
      body: JSON.stringify(
        {
          response: response,
        },
        null,
        2
      ),
    }
        
  } catch (error) {
      console.error('🚀 testDynamo - error.stack:', error.stack)
      return {
        statusCode: 400,
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Credentials': true
        },
        body: JSON.stringify(error.stack)
      }
  } 
}

I think I need to Restart ddbDc CLIENT with ROOT credentials in order to get this access to the ROOT resources.

How Can I do that?


Solution

  • You need to use STS AssumeRole and assume the role which you need to access that specific item/table.

    https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html

    const AWS = require('aws-sdk');
    const ddbDc = new AWS.DynamoDB.DocumentClient()
    const sts = new AWS.STS()
    
    
    module.exports.testDynamo = async event => {
      try {
        let result 
        let params = {}
        
        // Query Table B inside tenant
        params = {
          TableName: 'Table_B',
          Key: { externalKey : 'CA6E03C' }
        }
        result = await ddbDc.get(params).promise()
        console.log('🚀 result - ', result)  
    
        // Query Table A inside ROOT
        // Restart ddbDc CLIENT with ROOT credentials ?
        // https://aws.amazon.com/blogs/apn/isolating-saas-tenants-with-dynamically-generated-iam-policies/
        // https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
    
        const assumeRole = await sts
        .assumeRole({
          RoleArn: process.env.ROLE_ARN,
          RoleSessionName: process.env.ROLE_SESSION_NAME,
        })
        .promise()
    
        const credentials = new AWS.Credentials({
          accessKeyId: assumeRole.Credentials?.AccessKeyId,
          secretAccessKey: assumeRole.Credentials?.SecretAccessKey,
          sessionToken: assumeRole.Credentials?.SessionToken,
        })
    
        const dynamodb = new AWS.DynamoDB.DocumentClient({
          region: process.env.REGION,
          credentials: credentials,
        })
    
        params = {
          TableName: 'Table_A',
          Key: { externalKey : 'MAP_CA6E03C' }
        }
        result = await dynamodb.get(params).promise()
        console.log('🚀 result - ', result)
    
        // TODO merge table data
    
        return {
          statusCode: 200,
          headers: {
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Credentials': true
          },
          body: JSON.stringify(
            {
              response: response,
            },
            null,
            2
          ),
        }
            
      } catch (error) {
          console.error('🚀 testDynamo - error.stack:', error.stack)
          return {
            statusCode: 400,
            headers: {
              'Access-Control-Allow-Origin': '*',
              'Access-Control-Allow-Credentials': true
            },
            body: JSON.stringify(error.stack)
          }
      } 
    }