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:: :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:://index/*",
"arn:aws:dynamodb:eu-west-1::table/"
],
"Sid": "AllowDynamoDBReadWrite"
}
],
"Version": "2012-10-17"
}
How does AWS IAM Role Chaining work?
- Create an Assume Role Provider for Role-A
- Create an Assume Role Provider for Role-B by giving Role-A credentials
- 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();
}
Conclusion
Exceptionly blog has excellent tutorials for challenging languages methodologies or tools.
Feel free to explore some of my other posts in Java language;
One Response