Skip to content

Commit 7888b79

Browse files
committed
Support GCP Web Identity session credentials
1 parent 0fc87d7 commit 7888b79

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@
125125
<version>2.2</version>
126126
<scope>test</scope>
127127
</dependency>
128+
<dependency>
129+
<groupId>com.google.cloud</groupId>
130+
<artifactId>google-cloud-iamcredentials</artifactId>
131+
<version>2.0.2</version>
132+
</dependency>
128133
</dependencies>
129134

130135

src/main/java/io/prometheus/cloudwatch/CloudWatchCollector.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.yaml.snakeyaml.LoaderOptions;
2525
import org.yaml.snakeyaml.Yaml;
2626
import org.yaml.snakeyaml.constructor.SafeConstructor;
27+
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
2728
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
2829
import software.amazon.awssdk.regions.Region;
2930
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
@@ -39,11 +40,22 @@
3940
import software.amazon.awssdk.services.resourcegroupstaggingapi.model.TagFilter;
4041
import software.amazon.awssdk.services.sts.StsClient;
4142
import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider;
43+
import software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithWebIdentityCredentialsProvider;
4244
import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
45+
import software.amazon.awssdk.services.sts.model.AssumeRoleWithWebIdentityRequest;
46+
47+
import com.google.cloud.iam.credentials.v1.GenerateIdTokenRequest;
48+
import com.google.cloud.iam.credentials.v1.GenerateIdTokenResponse;
49+
import com.google.cloud.iam.credentials.v1.IamCredentialsClient;
4350

4451
public class CloudWatchCollector extends Collector implements Describable {
4552
private static final Logger LOGGER = Logger.getLogger(CloudWatchCollector.class.getName());
4653

54+
private static final String SERVICE_ACCOUNT_NAME_FORMAT = "projects/-/serviceAccounts/%s";
55+
56+
private static final int WEB_IDENTITY_CREDENTIAL_DURATION_SECONDS = 3600;
57+
58+
4759
static class ActiveConfig {
4860
ArrayList<MetricRule> rules;
4961
CloudWatchClient cloudWatchClient;
@@ -347,12 +359,55 @@ private void loadConfig(
347359
}
348360
}
349361

362+
private static String getIdToken(String serviceAccountEmail) throws IOException {
363+
try (IamCredentialsClient credentialsClient = IamCredentialsClient.create()) {
364+
GenerateIdTokenResponse idTokenResponse =
365+
credentialsClient.generateIdToken(
366+
GenerateIdTokenRequest.newBuilder()
367+
.setName(String.format(SERVICE_ACCOUNT_NAME_FORMAT, serviceAccountEmail))
368+
.setAudience(serviceAccountEmail)
369+
.setIncludeEmail(true)
370+
.build());
371+
return idTokenResponse.getToken();
372+
}
373+
}
374+
350375
private AwsCredentialsProvider getRoleCredentialProvider(Map<String, Object> config) {
376+
String roleArn = (String) config.get("role_arn");
377+
if (config.containsKey("assume_role_web_identity")) {
378+
// indicates we need to use gcp-based web identity to assume the role
379+
return StsAssumeRoleWithWebIdentityCredentialsProvider.builder()
380+
// intentionally using anonymous credentials since this is meant to be run only in gcp
381+
// environments, and the AssumeRoleWithWebIdentityRequest can run without any credentials
382+
.stsClient(
383+
StsClient.builder()
384+
.credentialsProvider(AnonymousCredentialsProvider.create())
385+
.region(Region.US_WEST_1)
386+
.build())
387+
.refreshRequest(
388+
() -> {
389+
String idToken;
390+
try {
391+
idToken = getIdToken((String) config.get("assume_role_web_identity"));
392+
} catch (IOException e) {
393+
throw new RuntimeException(
394+
"Failed to get id token for role arn: " + roleArn, e);
395+
}
396+
String[] roleSplit = roleArn.split("/");
397+
return AssumeRoleWithWebIdentityRequest.builder()
398+
.roleArn(roleArn)
399+
.webIdentityToken(idToken)
400+
.roleSessionName(roleSplit[roleSplit.length - 1])
401+
.durationSeconds(WEB_IDENTITY_CREDENTIAL_DURATION_SECONDS)
402+
.build();
403+
})
404+
.build();
405+
}
351406
StsClient stsClient =
352407
StsClient.builder().region(Region.of((String) config.get("region"))).build();
353408
AssumeRoleRequest assumeRoleRequest =
354409
AssumeRoleRequest.builder()
355-
.roleArn((String) config.get("role_arn"))
410+
.roleArn(roleArn)
356411
.roleSessionName("cloudwatch_exporter")
357412
.build();
358413
return StsAssumeRoleCredentialsProvider.builder()

0 commit comments

Comments
 (0)