Skip to content

Instantly share code, notes, and snippets.

@vatshat
Created January 25, 2019 08:56
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vatshat/f3fa2bbee59edcabf3d9cb4b04d88c72 to your computer and use it in GitHub Desktop.
Save vatshat/f3fa2bbee59edcabf3d9cb4b04d88c72 to your computer and use it in GitHub Desktop.
Java example of how to use AWS Cost Explorer API
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.services.costexplorer.AWSCostExplorer;
import com.amazonaws.services.costexplorer.AWSCostExplorerClientBuilder;
import com.amazonaws.services.costexplorer.model.*;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
import com.amazonaws.services.securitytoken.model.Credentials;
import com.amazonaws.services.route53domains.AmazonRoute53Domains;
import com.amazonaws.services.route53domains.AmazonRoute53DomainsClientBuilder;
import com.amazonaws.services.route53domains.model.*;
public class Test2 {
public static void main(String[] args) {
CEWithDimension();
CEWithGroupDefinition();
ViewBilling();
}
private static void CEWithGroupDefinition() {
final GetCostAndUsageRequest awsCERequest = new GetCostAndUsageRequest()
.withTimePeriod(new DateInterval().withStart("2018-04-01").withEnd("2018-04-30"))
.withGranularity(Granularity.DAILY)
.withMetrics("BlendedCost")
.withGroupBy(new GroupDefinition().withType("DIMENSION").withKey("INSTANCE_TYPE"));
try {
AWSCostExplorer ce = AWSCostExplorerClientBuilder.standard()
.withCredentials(new CredentialsClient().getCredentials())
.build();
GetCostAndUsageResult ceResult = ce.getCostAndUsage(awsCERequest);
ceResult.getResultsByTime().forEach(resultsByTime -> {
System.out.println(resultsByTime.toString());
});
} catch (final Exception e) {
System.out.println(e);
}
}
private static void CEWithDimension() {
Expression expression = new Expression();
DimensionValues dimensions = new DimensionValues();
dimensions.withKey(Dimension.SERVICE);
dimensions.withValues("Amazon Route 53");
expression.withDimensions(dimensions);
final GetCostAndUsageRequest awsCERequest = new GetCostAndUsageRequest()
.withTimePeriod(new DateInterval().withStart("2018-07-01").withEnd("2018-07-30"))
.withGranularity(Granularity.DAILY)
.withMetrics("BlendedCost")
.withFilter(expression);
try {
AWSCostExplorer ce = AWSCostExplorerClientBuilder.standard()
.withCredentials(new CredentialsClient().getCredentials())
.build();
System.out.println(ce.getCostAndUsage(awsCERequest));
} catch (final Exception e) {
System.out.println(e);
}
}
private static void ViewBilling() {
final ViewBillingRequest awsVBRequest = new ViewBillingRequest();
try {
AmazonRoute53Domains vb = AmazonRoute53DomainsClientBuilder.standard()
.withCredentials(new CredentialsClient().getCredentials())
.build();
ViewBillingResult vbResult = vb.viewBilling(awsVBRequest);
System.out.println(vbResult.getBillingRecords());
} catch (final Exception e) {
System.out.println(e);
}
}
}
class CredentialsClient{
CredentialsClient () {
}
public AWSStaticCredentialsProvider getCredentials() throws Exception {
AssumeRoleRequest assumeRole = new AssumeRoleRequest()
.withRoleArn("arn:aws:iam::1234567890:role/ec2-cli-access")
.withRoleSessionName("thabile-java-sdk");
AWSSecurityTokenService sts = AWSSecurityTokenServiceClientBuilder.standard().withRegion("us-east-1").build();
Credentials credentials = sts.assumeRole(assumeRole).getCredentials();
BasicSessionCredentials sessionCredentials = new BasicSessionCredentials(
credentials.getAccessKeyId(),
credentials.getSecretAccessKey(),
credentials.getSessionToken());
return new AWSStaticCredentialsProvider(sessionCredentials);
}
}
@ERAGON-JCV
Copy link

Nice

@Bharath-rudra
Copy link

Do we need to provide the access key, secret key and session token somewhere in the code or do they get injected directly through the roleArn?

@vatshat
Copy link
Author

vatshat commented Sep 18, 2020

Do we need to provide the access key, secret key and session token somewhere in the code or do they get injected directly through the roleArn?

Hi @Bharath-rudra,

Basically yes the credentials need to be provided somehow. But there are "various ways" of doing this and from "various locations"

  • regarding "various ways"

    1. an IAM user can assume the role provided in "withRoleArn". This means that you'll need to provide only "access key" and "secret key" (and no session token) which you got from the IAM console when initially creating the user. This is ideal if you're providing these credentials manually (refer to "various locations" below for more details)

    2. another IAM role can assume the role provided in "withRoleArn". This means that you'll need to provide "access key", "secret key" and "session token". This is ideal if a background process is automatically is generating these credentials for you (refer to various locations below for more details)

  • regarding "various locations" (listed in the order of the default chain)

    1. Manual process (in code) - YOU can specify credentials directly in the client

    2. Manual process (in OS) - YOU can specify the credentials in your environment variables

    3. Manual process (in code) - YOU can specify the credentials in your Java system properties

    4. Manual process (in OS) - YOU can specify the credentials in a file typically located at ~/.aws/credentials

    5. Automatic process - the EC2 service can provide the credentials for you in the EC2 meta data service at http://169.254.169.254/latest/meta-data/iam/security-credentials/ . For this to work YOU need to create an EC2 instance profile and attach your IAM role there , but you do this once off then the EC2 service will make sure that the latest temporary credentials are available in the meta data service. The Java SDK has built in functionality to know that if it doesn't find credentials in any of the above steps, it must get the credentials from the EC2 meta-data service at http://169.254.169.254/latest/meta-data/iam/security-credentials/

Please note that for all the "manual processes in OS" you can create a background process/application (e.g. bash script running on a cron job) which can update all those credentials for you. Although, that background will also need permissions/credentials to perform the AssumeRole API

In my example above, I was running this code on my local laptop at home in eclipse which was using permanent credentials which had AssumeRole permissions which I placed at ~/.aws/credentials

I wouldn't need the CredentialsClient class if I was running this on an EC2 instance with an Instance profile because the Java SDK would fetch them from the meta data service

@ablazleon
Copy link

Hi! First of all, thank you for sharing this code @vatshat , I'm struggling with writing this query, and this can help me a lot. I have a question, which libraries did you use to execute this query? I would be so thankful if anyone could share the pom.xml :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment