Configure cross-account access to Amazon DynamoDB - AWS Prescriptive Guidance

Configure cross-account access to Amazon DynamoDB

Created by Shashi Dalmia (AWS) and Jay Enjamoori (AWS)

Environment: Production

Technologies: DevOps; Databases; Security, identity, compliance

AWS services: Amazon DynamoDB; AWS Identity and Access Management; AWS Lambda

Summary

This pattern explains the steps for configuring cross-account access to Amazon DynamoDB. Amazon Web Services (AWS) services can access DynamoDB tables that are in the same AWS account if the service has the appropriate AWS Identity and Access Management (IAM) permissions set up in the database. However, access from a different AWS account requires setting up IAM permissions and establishing a trust relationship between the two accounts.

This pattern provides steps and sample code to demonstrate how you can configure AWS Lambda functions in one account to read and write to a DynamoDB table in a different account.

Prerequisites and limitations

  • Two active AWS accounts. This pattern refers to these accounts as Account A and Account B.

  • AWS Command Line Interface (AWS CLI) installed and configured to access Account A, to create the DynamoDB database. The other steps in this pattern provide instructions for using the IAM, DynamoDB, and Lambda consoles. If you’re planning to use AWS CLI instead, configure it to access both accounts.

Architecture

In the following diagram, AWS Lambda, Amazon EC2, and DynamoDB are all in the same account. In this scenario, Lambda functions and Amazon Elastic Compute Cloud (Amazon EC2) instances can access DynamoDB.

Accessing DynamoDB from the same account

If resources in a different AWS account try to access DynamoDB, they require setting up cross-account access and a trust relationship. For example, in the following diagram, to enable access between DynamoDB in Account A and the Lambda function in Account B, you must create a trust relationship between the accounts and grant appropriate access to the Lambda service and users, as described in the Epics section. 

Accessing DynamoDB from a different account

Tools

AWS services

  • Amazon DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability.

  • AWS Lambda is a compute service that supports running code without provisioning or managing servers. Lambda runs your code only when needed and scales automatically, from a few requests per day to thousands per second. You pay only for the compute time that you consume—there is no charge when your code is not running.

  • AWS Identity and Access Management (IAM) helps you securely manage access to your AWS resources by controlling who is authenticated and authorized to use them.

Code

This pattern includes sample code in the Additional information section to illustrate how you can configure a Lambda function in Account B to write and read from the DynamoDB table in Account A. The code is provided for illustration and testing purposes only. If you’re implementing this pattern in a production environment, use the code as a reference and customize it for your own environment.

This pattern illustrates cross-account access with Lambda and DynamoDB. You can use the same steps for other AWS services as well, but make sure that you grant and configure the appropriate permissions in both accounts. For example, if you want to grant access to an Amazon Relational Database Service (Amazon RDS) database in Account A, create a role for that database and bind it with a trust relationship. In Account B, if you want to use Amazon EC2 instead of AWS Lambda, create the respective IAM policy and role, and then attach them to the EC2 instance.

Epics

TaskDescriptionSkills required

Create a DynamoDB table in Account A.

After you configure AWS CLI for Account A, use the following AWS CLI command to create a DynamoDB table:

aws dynamodb create-table \ --table-name Table-Acccount-A \ --attribute-definitions \ AttributeName=category,AttributeType=S \ AttributeName=item,AttributeType=S \ --key-schema \ AttributeName=category,KeyType=HASH \ AttributeName=item,KeyType=RANGE \ --provisioned-throughput \ ReadCapacityUnits=5,WriteCapacityUnits=5

For more information about creating tables, see the DynamoDB documentation.

AWS DevOps
TaskDescriptionSkills required

Create a role in Account A.

This role will be used by Account B to gain permissions to access Account A. To create the role:

  1. Sign in to Account A at https://<account-ID-for-Account-A>.signin.aws.amazon.com/console.

  2. Open the IAM console at https://console.aws.amazon.com/iam/.

  3. In the navigation pane of the console, choose Roles, and then choose Create role.

  4. For Select trusted entity, choose AWS account, and in the An AWS account section, choose Another AWS account.

  5. For Account ID, enter the ID for Account B.

  6. Choose Next: Permissions.

  7. In the Filter policies box, enter DynamoDB.

  8. In the list of DynamoDB policies, select AmazonDynamoDBFullAccess.

    Note: This policy allows all actions on DynamoDB. As a security best practice, you should always grant only required permissions. For a list of other policies you can choose instead, see Example policies in the IAM documentation.

  9. Choose Next: Name, review, and create.

  10. For Role name, enter a unique name for your role (for example, DynamoDB-FullAccess-For-Account-B), and add an optional role description.

  11. Review all the sections and (optionally) add metadata to the role by attaching tags as key-value pairs.

  12. Choose Create role.

For more information about creating roles, see the IAM documentation.

AWS DevOps

Note the ARN for the role in Account A.

  1. In the navigation pane of the IAM console, choose Roles.

  2. In the search box, enter DynamoDB-FullAccess-For-Account-B (or the role name you created in the previous story), and choose the role.

  3. In the summary page for the role, copy the Amazon Resource Name (ARN). You’ll use the ARN when setting up the Lambda code in Account B.

AWS DevOps
TaskDescriptionSkills required

Create a policy to access Account A.

  1. Sign in to Account B at https://<account-ID-for-Account-B>.signin.aws.amazon.com/console.

  2. Open the IAM console at https://console.aws.amazon.com/iam/.

  3. In the navigation pane of the console, choose Policies, and then choose Create Policy.

  4. Choose the JSON tab.

  5. Type or paste the following JSON document:

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::<Account-A-ID>:role/DynamoDB-FullAccess-For-Account-B" } ] }

    where the Resource property contains the ARN of the role you created in the previous story in Account A.

  6. Choose Next: Tags.

  7. (Optional) Add metadata to the policy by attaching tags as key-value pairs.

  8. Choose Next: Review.

  9. For Policy name, enter a unique name for your policy (for example, DynamoDB-FullAccess-Policy-in-Account-A), and add an optional policy description.

  10. Choose Create policy.

For more information about creating policies, see the IAM documentation.

AWS DevOps

Create a role based on the policy.

This role is used by the Lambda functions in Account B to read from and write to the DynamoDB table in Account A.

  1. In Account B, in the navigation pane of the IAM console, choose Roles, and then choose Create role.

  2. For Select type of trusted entity, choose AWS service.

  3. For use case, choose Lambda.

  4. Choose Next: Permissions.

  5. In the Filter policies box, enter DynamoDB.

  6. In the list of DynamoDB policies, select DynamoDB-FullAccess-Policy-in-Account-A, which you created in the previous story.

  7. Choose Next: Name, review, and create.

  8. For Role name, enter a unique name for your role (for example, DynamoDB-FullAccess-in-Account-A), and add an optional role description.

  9. Review all the sections and (optionally) add metadata to the role by attaching tags as key-value pairs.

  10. Choose Create role.

You can now attach this role to the Lambda functions in the next epic.

For more information about creating roles, see the IAM documentation.

AWS DevOps
TaskDescriptionSkills required

Create a Lambda function to write data to DynamoDB.

  1. Sign in to Account B at https://<account-ID-for-Account-B>.signin.aws.amazon.com/console.

  2. Open the Lambda console at https://console.aws.amazon.com/lambda/.

  3. In the navigation pane of the console, choose Functions, and then choose Create function.

  4. For Name, enter lambda_write_function.

  5. For Runtime, choose Python 3.8 or later.

  6. For Permissions, Change default execution role, choose Use an existing role.

  7. For Existing role, choose DynamoDB-FullAccess-in-Account-A.

  8. Choose Create function.

  9. In the Code tab, paste the Lambda write function sample code provided in the Additional information section in this pattern. Make sure to provide the correct role ARN (from the epic Create a role in Account A) for the RoleArn field, and change region_name to where the DynamoDB table is created in account A (from the epic Create a DynamoDB table in Account A). Failing to do this results in a ResourceNotFoundException error.

  10. To deploy the code, choose Deploy.

  11. Run the function by choosing Test. This prompts you to configure a test event. Create a new event with your preferred name, such as MyTestEventForWrite, and save the configuration.

  12. Run the function again by choosing Test. This runs the code with the event name you provided.

  13. Check the output from the function. It should be similar to the output shown in the Lambda write function section of Additional information. This output indicates that the function accessed the DynamoDB table in Account A and was able to write data to it.

For more information about creating Lambda functions, see the Lambda documentation.

AWS DevOps

Create a Lambda function to read data from DynamoDB.

  1. In the navigation pane of the Lambda console, choose Functions, and then choose Create function.

  2. For Name, enter lambda_read_function.

  3. For Runtime, choose Python 3.8 or later.

  4. For Permissions, Change default execution role, choose Use an existing role.

  5. For Existing role, choose DynamoDB-FullAccess-in-Account-A.

  6. Choose Create function.

  7. In the Code tab, paste the Lambda read function sample code provided in Additional information section in this pattern. Make sure to provide the correct role ARN (from the epic Create a role in Account A) for the RoleArn field, and change region_name to where the DynamoDB table is created in account A (from the epic Create a DynamoDB table in Account A). Failing to do this results in a ResourceNotFoundException error.

  8. To deploy the code, choose Deploy.

  9. Run the function by choosing Test. This prompts you to configure a test event. Create a new event with your preferred name, such as MyTestEventForRead, and save the configuration.

  10. Run the function again by choosing Test. This runs the code with the event name you provided.

  11. Check the output from the function. It should be similar to the output shown in the Lambda read function section of Additional information. This output indicates that the function accessed the DynamoDB table in Account A and was able to read the data you added to the table.

For more information about creating Lambda functions, see the Lambda documentation.

AWS DevOps
TaskDescriptionSkills required

Delete the resources you created.

If you’re running this pattern in a testing or proof of concept (PoC) environment, delete the resources you created to avoid incurring costs.

  1. In Account B, delete the two Lambda functions and other resources you created to connect to DynamoDB.

  2. In Account A, delete the DynamoDB table you created.

  3. IAM policies do not cost anything, so you can keep them as is. However, for security, we recommend that you delete the following roles and policies you created for this pattern:

    • Account A: DymamoDB-Full-Access-for-Account-A role

    • Account B: DynamoDB-FullAccess-in-Account-A role

    • Account B: DynamoDB-FullAccess-Policy-in-Account-A policy

AWS DevOps

Related resources

Additional information

The code in this section is provided for illustration and testing purposes only. If you’re implementing this pattern in a production environment, use the code as a reference and customize it for your own environment.

Lambda write function

Sample code

import boto3 from datetime import datetime sts_client = boto3.client('sts') sts_session = sts_client.assume_role(RoleArn='arn:aws:iam::<Account-A ID>:role/DynamoDB-FullAccess-For-Account-B', RoleSessionName='test-dynamodb-session') KEY_ID = sts_session['Credentials']['AccessKeyId'] ACCESS_KEY = sts_session['Credentials']['SecretAccessKey'] TOKEN = sts_session['Credentials']['SessionToken'] dynamodb_client = boto3.client('dynamodb', region_name='<DynamoDB-table-region-in-account-A', aws_access_key_id=KEY_ID, aws_secret_access_key=ACCESS_KEY, aws_session_token=TOKEN) def lambda_handler(event, context): now = datetime.now() date_time = now.strftime("%m/%d/%Y, %H:%M:%S") data = dynamodb_client.put_item(TableName='Table-Acccount-A', Item={"category": {"S": "Fruit"},"item": {"S": "Apple"},"time": {"S": date_time}}) return data

Sample output

Sample output from Lambda write function

Lambda read function

Sample code

import boto3 from datetime import datetime sts_client = boto3.client('sts') sts_session = sts_client.assume_role(RoleArn='arn:aws:iam::<Account-A ID>:role/DynamoDB-FullAccess-For-Account-B', RoleSessionName='test-dynamodb-session') KEY_ID = sts_session['Credentials']['AccessKeyId'] ACCESS_KEY = sts_session['Credentials']['SecretAccessKey'] TOKEN = sts_session['Credentials']['SessionToken'] dynamodb_client = boto3.client('dynamodb', region_name='<DynamoDB-table-region-in-account-A>', aws_access_key_id=KEY_ID, aws_secret_access_key=ACCESS_KEY, aws_session_token=TOKEN) def lambda_handler(event, context): response = dynamodb_client.get_item(TableName='Table-Acccount-A', Key={'category':{'S':'Fruit'}, 'item':{'S':'Apple'}}) return response

Sample output

Sample output from Lambda read function