Add AWS credentials profile name parameter
Some Gerrit setups shares the AWS kinesis tables between AWS Regions,
for example multi-site setup in multiple regions. For security
reason access to the other regions should be limited to necessary
services. Add configuration param which allows to specify AWS
credentials profile to be used only by the events-aws-kinesis
plugin when connecting to the Kinesis. This profile allows us to
setup credentials or IAM Role with access to the Kinesis setup on
the other region.
Bug: Issue 16920
Change-Id: I64a1d945a113aae8c92443d9144dd3553fdb3a70
diff --git a/src/main/java/com/googlesource/gerrit/plugins/kinesis/Configuration.java b/src/main/java/com/googlesource/gerrit/plugins/kinesis/Configuration.java
index 9c04c09..34a1a8c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/kinesis/Configuration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/kinesis/Configuration.java
@@ -56,6 +56,7 @@
private final Long checkpointIntervalMs;
private final Level awsLibLogLevel;
private final Boolean sendAsync;
+ private final Optional<String> awsConfigurationProfileName;
@Inject
public Configuration(PluginConfigFactory configFactory, @PluginName String pluginName) {
@@ -115,13 +116,17 @@
.map(Boolean::new)
.orElse(DEFAULT_SEND_ASYNC);
+ this.awsConfigurationProfileName =
+ Optional.ofNullable(getStringParam(pluginConfig, "profileName", null));
+
logger.atInfo().log(
- "Kinesis client. Application:'%s'|PollingInterval: %s|maxRecords: %s%s%s",
+ "Kinesis client. Application:'%s'|PollingInterval: %s|maxRecords: %s%s%s%s",
applicationName,
pollingIntervalMs,
maxRecords,
region.map(r -> String.format("|region: %s", r.id())).orElse(""),
- endpoint.map(e -> String.format("|endpoint: %s", e.toASCIIString())).orElse(""));
+ endpoint.map(e -> String.format("|endpoint: %s", e.toASCIIString())).orElse(""),
+ awsConfigurationProfileName.map(p -> String.format("|profile: %s", p)).orElse(""));
}
public String getStreamEventsTopic() {
@@ -164,6 +169,10 @@
return initialPosition;
}
+ public Optional<String> getAwsConfigurationProfileName() {
+ return awsConfigurationProfileName;
+ }
+
private static String getStringParam(
PluginConfig pluginConfig, String name, String defaultValue) {
return Strings.isNullOrEmpty(System.getProperty(name))
diff --git a/src/main/java/com/googlesource/gerrit/plugins/kinesis/DynamoDbAsyncClientProvider.java b/src/main/java/com/googlesource/gerrit/plugins/kinesis/DynamoDbAsyncClientProvider.java
index f3812df..f359af9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/kinesis/DynamoDbAsyncClientProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/kinesis/DynamoDbAsyncClientProvider.java
@@ -14,9 +14,11 @@
package com.googlesource.gerrit.plugins.kinesis;
+import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClientBuilder;
@@ -35,6 +37,13 @@
configuration.getRegion().ifPresent(builder::region);
configuration.getEndpoint().ifPresent(builder::endpointOverride);
+ configuration
+ .getAwsConfigurationProfileName()
+ .ifPresent(
+ profile ->
+ builder.credentialsProvider(
+ (AwsCredentialsProvider) new ProfileCredentialsProvider(profile)));
+
return builder.build();
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisAsyncClientProvider.java b/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisAsyncClientProvider.java
index c983d60..8ad65b8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisAsyncClientProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisAsyncClientProvider.java
@@ -14,9 +14,11 @@
package com.googlesource.gerrit.plugins.kinesis;
+import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
import software.amazon.awssdk.services.kinesis.KinesisAsyncClientBuilder;
import software.amazon.kinesis.common.KinesisClientUtil;
@@ -35,7 +37,12 @@
KinesisAsyncClientBuilder builder = KinesisAsyncClient.builder();
configuration.getRegion().ifPresent(builder::region);
configuration.getEndpoint().ifPresent(builder::endpointOverride);
-
+ configuration
+ .getAwsConfigurationProfileName()
+ .ifPresent(
+ profile ->
+ builder.credentialsProvider(
+ (AwsCredentialsProvider) new ProfileCredentialsProvider(profile)));
return KinesisClientUtil.createKinesisAsyncClient(builder);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisProducerProvider.java b/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisProducerProvider.java
index 5c5dc52..341d650 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisProducerProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/kinesis/KinesisProducerProvider.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.kinesis;
+import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.kinesis.producer.KinesisProducer;
import com.amazonaws.services.kinesis.producer.KinesisProducerConfiguration;
import com.google.common.flogger.FluentLogger;
@@ -45,6 +46,9 @@
conf.setRegion(configuration.getRegion().orElseGet(regionProvider::getRegion).toString());
configuration
+ .getAwsConfigurationProfileName()
+ .ifPresent(profile -> conf.setCredentialsProvider(new ProfileCredentialsProvider(profile)));
+ configuration
.getEndpoint()
.ifPresent(
uri ->
@@ -54,12 +58,16 @@
.setCloudwatchPort(uri.getPort())
.setVerifyCertificate(false));
logger.atInfo().log(
- "Kinesis producer configured. Request Timeout (ms):'%s'%s%s",
+ "Kinesis producer configured. Request Timeout (ms):'%s'%s%s%s",
configuration.getPublishSingleRequestTimeoutMs(),
String.format("|region: '%s'", conf.getRegion()),
configuration
.getEndpoint()
.map(e -> String.format("|endpoint: '%s'", e.toASCIIString()))
+ .orElse(""),
+ configuration
+ .getAwsConfigurationProfileName()
+ .map(p -> String.format("|profile: '%s'", p))
.orElse(""));
return new KinesisProducer(conf);
diff --git a/src/main/resources/Documentation/Config.md b/src/main/resources/Documentation/Config.md
index 004ce0b..3562be2 100644
--- a/src/main/resources/Documentation/Config.md
+++ b/src/main/resources/Documentation/Config.md
@@ -109,6 +109,12 @@
The overall result of the operation, once available, will be logged.
Default: true
+`plugin.events-aws-kinesis.profileName`
+: Optional. The name of the aws configuration and credentials profile used to
+ connect to the Kinesis. See [Configuration and credential file settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)
+ Default: When not specified credentials are provided via the Default Credentials
+ Provider Chain, as explained [here](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html)
+
Overrides
=========================
diff --git a/src/test/java/com/googlesource/gerrit/plugins/kinesis/ConfigurationTest.java b/src/test/java/com/googlesource/gerrit/plugins/kinesis/ConfigurationTest.java
index 888c7f1..401838e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/kinesis/ConfigurationTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/kinesis/ConfigurationTest.java
@@ -19,6 +19,7 @@
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.PluginConfigFactory;
+import java.util.Optional;
import org.apache.log4j.Level;
import org.eclipse.jgit.lib.Config;
import org.junit.Before;
@@ -91,4 +92,27 @@
assertThat(configuration.isSendAsync()).isEqualTo(false);
}
+
+ @Test
+ public void shouldReturnAWSProfileNameWhenConfigured() {
+ String awsProfileName = "aws_profile_name";
+ pluginConfig.setString("profileName", awsProfileName);
+ when(pluginConfigFactoryMock.getFromGerritConfig(PLUGIN_NAME))
+ .thenReturn(pluginConfig.asPluginConfig());
+
+ Configuration configuration = new Configuration(pluginConfigFactoryMock, PLUGIN_NAME);
+ Optional<String> profileName = configuration.getAwsConfigurationProfileName();
+ assertThat(profileName.isPresent()).isTrue();
+ assertThat(profileName.get()).isEqualTo(awsProfileName);
+ }
+
+ @Test
+ public void shouldSkipAWSProfileNameWhenNotConfigured() {
+ when(pluginConfigFactoryMock.getFromGerritConfig(PLUGIN_NAME))
+ .thenReturn(pluginConfig.asPluginConfig());
+
+ Configuration configuration = new Configuration(pluginConfigFactoryMock, PLUGIN_NAME);
+ Optional<String> profileName = configuration.getAwsConfigurationProfileName();
+ assertThat(profileName.isPresent()).isFalse();
+ }
}