|
24 | 24 | import org.yaml.snakeyaml.LoaderOptions; |
25 | 25 | import org.yaml.snakeyaml.Yaml; |
26 | 26 | import org.yaml.snakeyaml.constructor.SafeConstructor; |
| 27 | +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; |
27 | 28 | import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; |
28 | 29 | import software.amazon.awssdk.regions.Region; |
29 | 30 | import software.amazon.awssdk.services.cloudwatch.CloudWatchClient; |
|
39 | 40 | import software.amazon.awssdk.services.resourcegroupstaggingapi.model.TagFilter; |
40 | 41 | import software.amazon.awssdk.services.sts.StsClient; |
41 | 42 | import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider; |
| 43 | +import software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithWebIdentityCredentialsProvider; |
42 | 44 | 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; |
43 | 50 |
|
44 | 51 | public class CloudWatchCollector extends Collector implements Describable { |
45 | 52 | private static final Logger LOGGER = Logger.getLogger(CloudWatchCollector.class.getName()); |
46 | 53 |
|
| 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 | + |
47 | 59 | static class ActiveConfig { |
48 | 60 | ArrayList<MetricRule> rules; |
49 | 61 | CloudWatchClient cloudWatchClient; |
@@ -347,12 +359,55 @@ private void loadConfig( |
347 | 359 | } |
348 | 360 | } |
349 | 361 |
|
| 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 | + |
350 | 375 | 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 | + } |
351 | 406 | StsClient stsClient = |
352 | 407 | StsClient.builder().region(Region.of((String) config.get("region"))).build(); |
353 | 408 | AssumeRoleRequest assumeRoleRequest = |
354 | 409 | AssumeRoleRequest.builder() |
355 | | - .roleArn((String) config.get("role_arn")) |
| 410 | + .roleArn(roleArn) |
356 | 411 | .roleSessionName("cloudwatch_exporter") |
357 | 412 | .build(); |
358 | 413 | return StsAssumeRoleCredentialsProvider.builder() |
|
0 commit comments