Using AWS SDK V2 for Java to read DynamoDB cross-account
omarrosadio
Posted on December 24, 2021
For medium and large size companies, is usual to have multiple AWS accounts grouped by functionality, environment, business goals, etc.
Sometimes, when is required cross-account access for resources, could be a problem due to the number of steps involved to grant access. And in the case of DynamoDB, additionally steps appears (different from services like KMS where you configure cross-account access and it is enough, for services like DynamoDB it is needed first assume the role and then procede with API calls).
In this sample, I will describe step by step how to configure permissions to allow DynamoDB cross account access and test it using AWS SDK V2 for Java deployed in EC2 (however, the same concept could be applied to AWS Lambda).
Scenario
Access from an Java Application on Account "A" to and DynamoDB Table on Account "B".
Diagram of resources to be created
Considerations
- Account owner of DynamoDB Tables will be referenced as "Account A".
- Account in which Java Application will be deployed and need access to Tables from "Account A", will be reference as "Account B".
- Complete Java Code can be found on this repository. It uses maven as dependency manager and AWS SDK V2 for Java.
Steps
1. Create Role on Account A (DynamoDB resources owner)
On account A, create a Role and choose "Another AWS Account" as type of trusted entity. Enter the Account ID from Account B:
For permissions policies, I am attaching "AmazonDynamoDBReadOnlyAccess" managed policy only for demo purposes, but on real usage it should follow the Principle of Least Privilege to limit access.
Create the role, choose a suitable role name:
Copy the Role ARN because it will be used in the next step:
arn:aws:iam::<ID_Account_B>:role/CrossAccountReadDynamo
2. Create policy on Account B with permissions to assume role created on step 1
On Account B, create a Policy to grant permissions to assume the role from Account A. For policy JSON use:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<ID_Account_A>:role/CrossAccountReadDynamo"
}
}
And choose a name for the policy:
assume_role_account_A
3. Create role on Account B and attach the policy created on step 2
On Account B, create a role and select EC2 as type of trusted entity:
Attach the policy recently created:
Name: EC2_AssumeRole_Account_A
4. Test cross account access through Java Application
The Java Application will be deployed on and EC2 Instance in Account B. This EC2 Instance needs to has attached the Role created previously.
The first step on code requires make an API Call to the Security Token Service (AWS STS) and in this way generate temporary credentials to be able to assume the role from Account A.
Modify the variables accordingly:
- roleARN: substitute with Role ARN created on step 1
- roleSessionName: an identifier to the temporary session
- region: region where the DynamoDB resources are deployed
/*Change this variables according to the role created*/
String roleARN = "arn:aws:iam::<ACCOUNT_A>:role/<ROLE_NAME>";
String roleSessionName = "DynamoCrossAccount";
Region region = Region.US_EAST_1;
Once the temporary credentials are generated, is needed to set the AccessKey, SecretAccessKey and SessionToken:
AwsSessionCredentials awsCreds = AwsSessionCredentials.create(myCreds.accessKeyId(), myCreds.secretAccessKey(),
myCreds.sessionToken());
With the new credentials configured, the subsequents API Calls will be used the role from Account A. So, now we can consume and do operations over DynamoDB Tables of Account A. To test it, I will list all the existing tables:
ListTablesResponse response = null;
if (lastName == null) {
ListTablesRequest request = ListTablesRequest.builder().limit(10).build();
response = ddb.listTables(request);
} else {
ListTablesRequest request = ListTablesRequest.builder().exclusiveStartTableName(lastName).build();
response = ddb.listTables(request);
}
List<String> tableNames = response.tableNames();
if (tableNames.size() > 0) {
for (String curName : tableNames) {
System.out.format("* %s\n", curName);
}
} else {
System.out.println("No tables found!");
System.exit(0);
}
lastName = response.lastEvaluatedTableName();
if (lastName == null) {
moreTables = false;
}
And the expected output should list resources from the other account. Achieving cross-account access:
Again, the complete code is on GitHub and it is based on Official AWS documentation, specifically:
Posted on December 24, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.