I want to use Java to access Dynamodb on an Ec2 instance. This Ec2 instance has been granted a IAM role, with which I can directly access the Dynamodb by using aws CLI: aws dynamodb list-table. Now I try to access the Dynamodb via Java. The Java code should be able to assume role, but it didn't work.
public static void main(String[] args) throws Exception {
String ROLE_ARN = "arn:aws:iam::....";
AWSSecurityTokenServiceClient stsClient = new AWSSecurityTokenServiceClient();
AssumeRoleRequest assumeRequest = new AssumeRoleRequest()
.withRoleArn(ROLE_ARN)
.withDurationSeconds(3600)
.withRoleSessionName("demo");
AssumeRoleResult assumeResult = stsClient.assumeRole(assumeRequest);
BasicSessionCredentials temporaryCredentials = new BasicSessionCredentials(
assumeResult.getCredentials().getAccessKeyId(),
assumeResult.getCredentials().getSecretAccessKey(),
assumeResult.getCredentials().getSessionToken());
AmazonDynamoDBClient client = new AmazonDynamoDBClient(temporaryCredentials)
DynamoDB dynamoDB = new DynamoDB(client);
TableCollection<ListTablesResult> tables = dynamoDB.listTables();
Iterator<Table> iterator_t = tables.iterator();
System.out.println("Listing table names");
while (iterator_t.hasNext()) {
Table table = iterator_t.next();
System.out.println(table.getTableName());
}
}
When I ran the code on the ec2 instance, I got
Exception in thread "main" com.amazonaws.services.securitytoken.model.AWSSecurityTokenServiceException: Not authorized to perform sts:AssumeRole (Service: AWSSecurityTokenService; Status Code: 403; Error Code: AccessDenied; Request ID: 60313562-d462-11e6-a116-5bf8bb6a59ce)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1586)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1254)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1035)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:747)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:721)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:704)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:672)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:654)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:518)
at com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient.doInvoke(AWSSecurityTokenServiceClient.java:1188)
at com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient.invoke(AWSSecurityTokenServiceClient.java:1164)
at com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient.assumeRole(AWSSecurityTokenServiceClient.java:419)
at com.spokeo.dynamo_elas.AccessAwsD.main(AccessAwsD.java:stsClient.assumeRole(assumeRequest))
Anybody knows how to solve this problem? Thanks.
When you use a role, you don't have to distribute long-term credentials (such as a user name and password or access keys) to an Amazon EC2 instance. Instead, the role supplies temporary permissions that applications can use when they make calls to other AWS resources.
A VPC endpoint for DynamoDB enables Amazon EC2 instances in your VPC to use their private IP addresses to access DynamoDB with no exposure to the public internet. Your EC2 instances do not require public IP addresses, and you don't need an internet gateway, a NAT device, or a virtual private gateway in your VPC.
After a long time exploring, finally figured out the following solution.
AWSCredentialsProvider provider = new InstanceProfileCredentialsProvider();
AWSCredentials credential = provider.getCredentials();
AmazonDynamoDBClient client = new AmazonDynamoDBClient(credential);
client.setRegion(Region.getRegion(Regions.US_WEST_2));
DynamoDB dynamoDB = new DynamoDB(client);
TableCollection<ListTablesResult> tables = dynamoDB.listTables();
Also the dependencies in pom.xml needs to be configured correctly to avoid conflicts, say, com.amazonaws aws-java-sdk 1.11.72
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-cbor -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-cbor</artifactId>
<version>2.8.5</version>
</dependency>
When I've done this I've never had to do anything specifically with the role - indeed, I have no idea what role I'm using. I use something like:
AWSCredentialsProviderChain credentialsProvider;
try {
credentialsProvider = new DefaultAWSCredentialsProviderChain();
}
catch (Exception e) {
throw new RuntimeException("Error loading credentials", e);
}
AmazonDynamoDBClient client = new AmazonDynamoDBClient(credentialsProvider);
The advantage of using the default provider is that if I'm developing locally with a ~/.aws/credentials it is used. If I'm on the EC2 with IAM credentials then it is used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With