skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    Using Lambda function and Serverless Framework do this:

    npm install --save-dev serverless-iam-roles-per-function to install serverless-iam-roles-per-function. Link

    ...
    plugins:
      - serverless-iam-roles-per-function
    ...
    
    functions:
      listComponentsRootDynamo:
        ...
        ...
        iamRoleStatements:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Resource: "arn:aws:iam::RootID:role/roleName"
    

    It will grant access to this lambda function listComponentsRootDynamo the access to Root-DynamoDb Table inside the Control Tower ROOT account.

    Note that the role that provide that access to the Dynamo specific tables must exist in the ROOT-IAM Roles. Just copy its Role ARN in the Resource: portion of iamRoleStatements:.

    Here is an example of the Role inside Root that provides that access to a specific Dynamo Table <DynamoDb-Table-Name>:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "dynamodb:*"
                ],
                "Resource": [
                    "arn:aws:dynamodb:us-east-1:Root-Id:table/<DynamoDb-Table-Name>",
                    "arn:aws:dynamodb:us-east-1:Root-Id:table/<DynamoDb-Table-Name>/index/*"
                ],
                "Effect": "Allow",
                "Sid": ""
            }
        ]
    }
    

    And Following the Lee Hannigan answer do this inside the Lambda that will query the Root - DynamoDb Table:

    'use strict';
    
    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)
          }
      } 
    }
    

  2. 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)
          }
      } 
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search