AWS IAM Role Chaining in Java – DynamoDB, S3

AWS IAM Role Chaining Using Java, S3, and Dynamodb

Table of Contents

Choosing between IAM roles or IAM users for accessing AWS resources is a matter of risk appetite you are taking. But for the fact, AWS encourages you to use IAM roles over the users. 

IAM roles provide temporary credentials with the least privilege. However, unlike IAM users, it cannot make direct requests to an AWS resource; therefore, it is supposed to be assumed by an authorized entity such as IAM users, applications, or an EC2 service.

This tutorial aims for a walkthrough guide about using the “IAM role chaining between cross-accounts for accessing a resource such as DynamoDB or S3 Storage in Java language”.

Grant access to the IAM Roles 

For the AWS role chaining example, I will proceed with the assumptions below;

  • I have two different AWS accounts that I named Account-A and Account-B
  • The application instance is running in Account-A
  • The resources I want to access are in Account-B (DynamoDB and S3)

I imagine that I will need two different roles for such a scenario.

Cross Account Sign Role

Cross account access between Account-A and Account-B. This role provides the service instance access from Account-A to Account-B.

Role-1: 

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

 ** the permissions will be specified in the CrossAccountSignRole policy based on your needs!

DynamoDB Execution Role

This role will grant access to service instances for running queries over desired AWS resources such as DynamoDB or S3

Role-2:

				
					   "Statement": [
        {
            "Action": [
                "dynamodb:DeleteItem",
                "dynamodb:DescribeTable",
                "dynamodb:GetItem",
                "dynamodb:BatchGetItem",
                "dynamodb:UpdateTimeToLive",
                "dynamodb:BatchWriteItem",
                "dynamodb:PutItem",
                "dynamodb:Scan",
                "dynamodb:Query",
                "dynamodb:UpdateItem",
                "dynamodb:UpdateTable",
                "dynamodb:ListTables",
                "dynamodb:List*"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:eu-west-1:<Account-ID>:<Table-Name>//index/*",
                "arn:aws:dynamodb:eu-west-1:<Account-ID>:table/<Table-Name>"
            ],
            "Sid": "AllowDynamoDBReadWrite"
        }
    ],
    "Version": "2012-10-17"
}
				
			

How does AWS IAM Role Chaining work?

  1. Create an Assume Role Provider for Role-A
  2. Create an Assume Role Provider for Role-B by giving Role-A credentials
  3. Use the Role-B provider as credentials for DynamoDB or S3 clients.

AWS IAM Role Chaining Example in Java

Creating STS Client in Java

				
					private static AWSSecurityTokenServiceClientBuilder getStsClient(StsProperties props) {
 return AWSSecurityTokenServiceClientBuilder
     .standard()
     .withRegion(Regions.fromName(props.getRegion()))
     .withClientConfiguration(getProxyClientConfig(props.getProxyHost(), props.getProxyPort()));
}
				
			

Creating Proxy Client

Ideally, you will have a proxy server that brings an extra layer of security to protect you from data breaches and most hacker attacks, so the below code piece will show how to create a proxy client and attach it to the STS client later.

				
					private static ClientConfiguration getProxyClientConfig(String proxyHost, String proxyPort) {
 ClientConfiguration clientConfiguration = new ClientConfiguration();
 clientConfiguration.setProxyHost(proxyHost);
 clientConfiguration.setProxyPort(Integer.parseInt(proxyPort));
 return clientConfiguration;
}
				
			

Chaining Roles with AWS Assume Role Credentials Provider

STSAssumeRoleSessionCredentialsProvider uses the AWS Security Token Service to assume a Role, and it creates temporary sessions for authentication. This provider will refresh credentials automatically with a background thread based on your duration specification. If you don’t want to use the auto-refresh mechanism that comes ready on your plate by AWS, you can create a custom credentials provider and override with your setup.

				
					public static STSAssumeRoleSessionCredentialsProvider getAWSCredentialsProviderChain(StsProperties props) {
 final String dynamoDbSessionName = "dynamodb-session-" + UUID.randomUUID();
 final String crossAccountSessionName = "cross-account-session-" + UUID.randomUUID();

 STSAssumeRoleSessionCredentialsProvider crossAccountProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(props.getRoleArn(), crossAccountSessionName)
     .withExternalId(props.getExternalId())
     .withRoleSessionDurationSeconds(SESSION_DURATION_IN_SECONDS)
     .withStsClient(getStsClient(props).build())
     .build();

 return new STSAssumeRoleSessionCredentialsProvider.Builder(props.getExecutionRoleArn(), dynamoDbSessionName)
     .withExternalId(props.getExecutionRoleExternalId())
     .withRoleSessionDurationSeconds(SESSION_DURATION_IN_SECONDS)
     .withStsClient(getStsClient(props).withCredentials(crossAccountProvider).build())
     .build();
}
				
			

How to Use AWS Credentials Provider in DynamoDB or S3?

Create DynamoDB Client with AWS Assume Role Credential Provider

				
					public AmazonDynamoDB amazonDynamoDB() {
 return AmazonDynamoDBClientBuilder.standard()
     .withRegion(Regions.EU_WEST_1)
     .withCredentials(getAWSCredentialsProviderChain(props))
     .build();
}
				
			

Create S3 Client with AWS Assume Role Credential Provider

				
					public AmazonS3 getS3Client(StsProperties stsProperties) {
   return AmazonS3Client.builder()
           .withCredentials(getAWSCredentialsProviderChain(props))
           .withRegion(Regions.EU_WEST_1)
           .build();
}
				
			

Leave a Reply

Your email address will not be published.