diff --git a/bom/pom.xml b/bom/pom.xml
index 1cd014286..b3767bdc5 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -147,6 +147,16 @@
quarkus-amazon-secretsmanager-deployment
${project.version}
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-secretsmanager-config
+ ${project.version}
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-secretsmanager-config-deployment
+ ${project.version}
+
io.quarkiverse.amazonservices
quarkus-amazon-devservices-ses
diff --git a/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AbstractAmazonServiceProcessor.java b/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AbstractAmazonServiceProcessor.java
index df2b48bb6..7f0fa3059 100644
--- a/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AbstractAmazonServiceProcessor.java
+++ b/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AbstractAmazonServiceProcessor.java
@@ -87,10 +87,10 @@ protected void setupExtension(
//Discover all clients injections in order to determine if async or sync client is required
for (RequireAmazonClientBuildItem clientRequirement : clientRequirements) {
- if (clientRequirement.getSyncClassName().filter(syncClientName()::equals).isPresent()) {
+ if (clientRequirement.getSyncClassName().filter(p -> syncClientName().equals(p)).isPresent()) {
syncClassName = Optional.of(syncClientName());
}
- if (clientRequirement.getAsyncClassName().filter(asyncClientName()::equals).isPresent()) {
+ if (clientRequirement.getAsyncClassName().filter(p -> asyncClientName().equals(p)).isPresent()) {
asyncClassName = Optional.of(asyncClientName());
}
}
@@ -220,7 +220,7 @@ protected void createClientBuilders(
.scope(ApplicationScoped.class)
.runtimeValue(syncClientBuilder)
.done());
- clientSync.produce(new AmazonClientSyncResultBuildItem(configName));
+ clientSync.produce(new AmazonClientSyncResultBuildItem(configName, syncClientBuilder));
}
if (asyncClientBuilder != null) {
asyncClientBuilder = recorder.configure(asyncClientBuilder, awsConfigRuntime, sdkConfigRuntime,
@@ -230,7 +230,7 @@ protected void createClientBuilders(
.scope(ApplicationScoped.class)
.runtimeValue(asyncClientBuilder)
.done());
- clientAsync.produce(new AmazonClientAsyncResultBuildItem(configName));
+ clientAsync.produce(new AmazonClientAsyncResultBuildItem(configName, asyncClientBuilder));
}
if (presignerBuilder != null) {
presignerBuilder = recorder.configurePresigner(presignerBuilder, awsConfigRuntime, sdkConfigRuntime,
diff --git a/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientAsyncResultBuildItem.java b/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientAsyncResultBuildItem.java
index 1ebbdb8c8..923b752d2 100644
--- a/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientAsyncResultBuildItem.java
+++ b/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientAsyncResultBuildItem.java
@@ -1,6 +1,8 @@
package io.quarkus.amazon.common.deployment;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.runtime.RuntimeValue;
+import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
/*
* Describes what async clients are provided by a given extension
@@ -8,12 +10,18 @@
public final class AmazonClientAsyncResultBuildItem extends MultiBuildItem {
private final String awsClientName;
+ private RuntimeValue asyncClientBuilder;
- public AmazonClientAsyncResultBuildItem(String awsClientName) {
+ public AmazonClientAsyncResultBuildItem(String awsClientName, RuntimeValue asyncClientBuilder) {
this.awsClientName = awsClientName;
+ this.asyncClientBuilder = asyncClientBuilder;
}
public String getAwsClientName() {
return awsClientName;
}
+
+ public RuntimeValue getAsyncClientBuilder() {
+ return asyncClientBuilder;
+ }
}
diff --git a/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientSyncResultBuildItem.java b/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientSyncResultBuildItem.java
index 2f2305f70..260564148 100644
--- a/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientSyncResultBuildItem.java
+++ b/common/deployment/src/main/java/io/quarkus/amazon/common/deployment/AmazonClientSyncResultBuildItem.java
@@ -1,6 +1,8 @@
package io.quarkus.amazon.common.deployment;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.runtime.RuntimeValue;
+import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
/*
* Describes what sync clients are provided by a given extension
@@ -8,12 +10,18 @@
public final class AmazonClientSyncResultBuildItem extends MultiBuildItem {
private final String awsClientName;
+ private RuntimeValue syncClientBuilder;
- public AmazonClientSyncResultBuildItem(String awsClientName) {
+ public AmazonClientSyncResultBuildItem(String awsClientName, RuntimeValue syncClientBuilder) {
this.awsClientName = awsClientName;
+ this.syncClientBuilder = syncClientBuilder;
}
public String getAwsClientName() {
return awsClientName;
}
+
+ public RuntimeValue getSyncClientBuilder() {
+ return syncClientBuilder;
+ }
}
diff --git a/pom.xml b/pom.xml
index f9913970d..652e56c9e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,7 @@
ssm
sts
secretsmanager
+ secretsmanager-config
docs
integration-tests
diff --git a/secretsmanager-config/deployment/pom.xml b/secretsmanager-config/deployment/pom.xml
new file mode 100644
index 000000000..67ccdfe59
--- /dev/null
+++ b/secretsmanager-config/deployment/pom.xml
@@ -0,0 +1,65 @@
+
+
+ 4.0.0
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-secretsmanager-config-parent
+ 999-SNAPSHOT
+
+
+ quarkus-amazon-secretsmanager-config-deployment
+ Quarkus - Amazon Services - Secrets Manager Config - Deployment
+
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-common-deployment
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-common-deployment-spi
+
+
+ io.quarkus
+ quarkus-credentials-deployment
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-secretsmanager-config
+
+
+ software.amazon.awssdk
+ url-connection-client
+
+
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${quarkus.version}
+
+
+
+
+
+
+
diff --git a/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigDevServicesProcessor.java b/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigDevServicesProcessor.java
new file mode 100644
index 000000000..953f33561
--- /dev/null
+++ b/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigDevServicesProcessor.java
@@ -0,0 +1,54 @@
+package io.quarkus.amazon.secretsmanager.config.deployment;
+
+import java.util.Map;
+
+import org.testcontainers.containers.localstack.LocalStackContainer;
+import org.testcontainers.containers.localstack.LocalStackContainer.Service;
+
+import io.quarkus.amazon.common.deployment.spi.AbstractDevServicesLocalStackProcessor;
+import io.quarkus.amazon.common.deployment.spi.DevServicesLocalStackProviderBuildItem;
+import io.quarkus.amazon.common.runtime.DevServicesBuildTimeConfig;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigBuildTimeConfig;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerDevServicesBuildTimeConfig;
+import io.quarkus.deployment.annotations.BuildStep;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+
+public class SecretsManagerConfigDevServicesProcessor extends AbstractDevServicesLocalStackProcessor {
+
+ @BuildStep
+ DevServicesLocalStackProviderBuildItem setupSecretsManager(SecretsManagerConfigBuildTimeConfig clientBuildTimeConfig) {
+ return this.setup(Service.SECRETSMANAGER, clientBuildTimeConfig.devservices);
+ }
+
+ @Override
+ protected void overrideDefaultConfig(Map defaultConfig) {
+ for (String key : defaultConfig.keySet().toArray(new String[0])) {
+ defaultConfig.put(key.replace(Service.SECRETSMANAGER.getName(), Service.SECRETSMANAGER.getName() + "-config"),
+ defaultConfig.remove(key));
+ }
+ }
+
+ @Override
+ protected void prepareLocalStack(DevServicesBuildTimeConfig clientBuildTimeConfig,
+ LocalStackContainer localstack) {
+ createSecrets(localstack, (SecretsManagerDevServicesBuildTimeConfig) clientBuildTimeConfig);
+ }
+
+ public void createSecrets(LocalStackContainer localstack, SecretsManagerDevServicesBuildTimeConfig configuration) {
+ try (SecretsManagerClient client = SecretsManagerClient.builder()
+ .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+ .region(Region.of(localstack.getRegion()))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials
+ .create(localstack.getAccessKey(), localstack.getSecretKey())))
+ .httpClientBuilder(UrlConnectionHttpClient.builder())
+ .build()) {
+ configuration.secrets.forEach((key, value) -> {
+ client.createSecret(r -> r.name(key).secretString(value));
+ });
+ }
+ }
+}
diff --git a/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigProcessor.java b/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigProcessor.java
new file mode 100644
index 000000000..d3e46a1b5
--- /dev/null
+++ b/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigProcessor.java
@@ -0,0 +1,136 @@
+package io.quarkus.amazon.secretsmanager.config.deployment;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.jboss.jandex.DotName;
+
+import io.quarkus.amazon.common.deployment.AbstractAmazonServiceProcessor;
+import io.quarkus.amazon.common.deployment.AmazonClientBuildItem;
+import io.quarkus.amazon.common.deployment.AmazonClientInterceptorsPathBuildItem;
+import io.quarkus.amazon.common.deployment.AmazonClientSyncResultBuildItem;
+import io.quarkus.amazon.common.deployment.AmazonClientSyncTransportBuildItem;
+import io.quarkus.amazon.common.deployment.RequireAmazonClientBuildItem;
+import io.quarkus.amazon.common.runtime.AmazonClientRecorder;
+import io.quarkus.amazon.common.runtime.AmazonClientUrlConnectionTransportRecorder;
+import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig;
+import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig.SyncClientType;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigBuildTimeConfig;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigConfig;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigRecorder;
+import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.RunTimeConfigurationSourceValueBuildItem;
+import io.quarkus.runtime.RuntimeValue;
+import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClientBuilder;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder;
+
+public class SecretsManagerConfigProcessor extends AbstractAmazonServiceProcessor {
+
+ private static final String AMAZON_SECRETS_MANAGER_CONFIG = "amazon-secretsmanager-config";
+
+ SecretsManagerConfigBuildTimeConfig buildTimeConfig;
+
+ @Override
+ protected String amazonServiceClientName() {
+ return AMAZON_SECRETS_MANAGER_CONFIG;
+ }
+
+ @Override
+ protected String configName() {
+ return "secretsmanager-config";
+ }
+
+ @Override
+ protected DotName syncClientName() {
+ return DotName.createSimple(SecretsManagerClient.class.getName());
+ }
+
+ @Override
+ protected DotName asyncClientName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected String builtinInterceptorsPath() {
+ return "software/amazon/awssdk/services/secretsmanager/execution.interceptors";
+ }
+
+ @BuildStep
+ @Record(ExecutionTime.RUNTIME_INIT)
+ public RunTimeConfigurationSourceValueBuildItem configure(SecretsManagerConfigRecorder recorder,
+ SecretsManagerConfigConfig config, SecretsManagerConfigBuildTimeConfig buildTimeConfig,
+ List syncClientBuilders) {
+
+ String configName = configName();
+
+ RuntimeValue syncClientBuilder = (RuntimeValue) syncClientBuilders
+ .stream().filter(s -> configName.equals(s.getAwsClientName())).findFirst().get().getSyncClientBuilder();
+
+ return new RunTimeConfigurationSourceValueBuildItem(
+ recorder.configSources(config, buildTimeConfig, syncClientBuilder));
+ }
+
+ @BuildStep
+ void setup(List clientRequirements,
+ BuildProducer extensionSslNativeSupport,
+ BuildProducer feature,
+ BuildProducer interceptors,
+ BuildProducer clientProducer) {
+
+ SyncHttpClientBuildTimeConfig syncClientConfig = new SyncHttpClientBuildTimeConfig();
+ syncClientConfig.type = SyncClientType.URL;
+
+ setupExtension(List.of(new RequireAmazonClientBuildItem(Optional.of(syncClientName()), Optional.empty())),
+ extensionSslNativeSupport, feature, interceptors, clientProducer,
+ buildTimeConfig.sdk, syncClientConfig);
+ }
+
+ @BuildStep
+ @Record(ExecutionTime.RUNTIME_INIT)
+ void setupUrlConnectionSyncTransport(List amazonClients, SecretsManagerConfigRecorder recorder,
+ AmazonClientUrlConnectionTransportRecorder transportRecorder,
+ SecretsManagerConfigConfig runtimeConfig, BuildProducer syncTransports) {
+ SyncHttpClientBuildTimeConfig syncClientConfig = new SyncHttpClientBuildTimeConfig();
+ syncClientConfig.type = SyncClientType.URL;
+
+ createUrlConnectionSyncTransportBuilder(amazonClients,
+ transportRecorder,
+ syncClientConfig,
+ recorder.getSyncConfig(runtimeConfig),
+ syncTransports);
+ }
+
+ @BuildStep
+ @Record(ExecutionTime.RUNTIME_INIT)
+ void createClientBuilders(SecretsManagerConfigRecorder recorder,
+ AmazonClientRecorder commonRecorder,
+ SecretsManagerConfigConfig runtimeConfig,
+ List syncTransports,
+ BuildProducer syntheticBeans,
+ BuildProducer clientSync) {
+
+ createClientBuilders(commonRecorder,
+ recorder.getAwsConfig(runtimeConfig),
+ recorder.getSdkConfig(runtimeConfig),
+ buildTimeConfig.sdk,
+ syncTransports,
+ List.of(),
+ SecretsManagerClientBuilder.class,
+ (syncTransport) -> recorder.createSyncBuilder(runtimeConfig, syncTransport),
+ SecretsManagerAsyncClientBuilder.class,
+ null,
+ null,
+ null,
+ syntheticBeans,
+ clientSync,
+ null);
+ }
+}
diff --git a/secretsmanager-config/deployment/src/test/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigTest.java b/secretsmanager-config/deployment/src/test/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigTest.java
new file mode 100644
index 000000000..02198ea81
--- /dev/null
+++ b/secretsmanager-config/deployment/src/test/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigTest.java
@@ -0,0 +1,40 @@
+package io.quarkus.amazon.secretsmanager.config.deployment;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.junit.Assert;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusUnitTest;
+
+public class SecretsManagerConfigTest {
+
+ @ConfigProperty(name = "mysecretkey")
+ String secret;
+
+ @ConfigProperty(name = "myprefix.mysecretkey")
+ String secretWithPrefix;
+
+ @ConfigProperty(name = "otherprefix.mysecretkey")
+ String secretWithOtherPrefix;
+
+ @ConfigProperty(name = "disabledprefix.mysecretkey", defaultValue = "unset")
+ String secretWithDisabledPrefix;
+
+ @ConfigProperty(name = "othersecretkey", defaultValue = "unset")
+ String unset;
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .withApplicationRoot((jar) -> jar
+ .addAsResource("devservices.properties", "application.properties"));
+
+ @Test
+ public void test() {
+ Assert.assertEquals("mysecretvalue", secret);
+ Assert.assertEquals("mysecretvalue", secretWithPrefix);
+ Assert.assertEquals("mysecretvalue", secretWithOtherPrefix);
+ Assert.assertEquals("unset", secretWithDisabledPrefix);
+ Assert.assertEquals("unset", unset);
+ }
+}
diff --git a/secretsmanager-config/deployment/src/test/resources/devservices.properties b/secretsmanager-config/deployment/src/test/resources/devservices.properties
new file mode 100644
index 000000000..82a6f6122
--- /dev/null
+++ b/secretsmanager-config/deployment/src/test/resources/devservices.properties
@@ -0,0 +1,7 @@
+quarkus.secretsmanager-config.devservices.secrets.mysecretkey=mysecretvalue
+quarkus.secretsmanager-config.devservices.secrets.othersecretkey=othersecretvalue
+
+quarkus.secretsmanager-config.filter.name-prefix=mysecret
+quarkus.secretsmanager-config.filter.myprefix.name-prefix=mysecret
+quarkus.secretsmanager-config.filter.otherprefix.enabled=true
+quarkus.secretsmanager-config.filter.disabledprefix.enabled=false
diff --git a/secretsmanager-config/pom.xml b/secretsmanager-config/pom.xml
new file mode 100644
index 000000000..c257385cf
--- /dev/null
+++ b/secretsmanager-config/pom.xml
@@ -0,0 +1,21 @@
+
+
+ 4.0.0
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-services-build-parent
+ 999-SNAPSHOT
+ ../build-parent/pom.xml
+
+
+ quarkus-amazon-secretsmanager-config-parent
+ Quarkus - Amazon Services - Secrets Manager Config
+ pom
+
+
+ runtime
+ deployment
+
+
+
diff --git a/secretsmanager-config/runtime/pom.xml b/secretsmanager-config/runtime/pom.xml
new file mode 100644
index 000000000..05e084ea1
--- /dev/null
+++ b/secretsmanager-config/runtime/pom.xml
@@ -0,0 +1,60 @@
+
+
+ 4.0.0
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-secretsmanager-config-parent
+ 999-SNAPSHOT
+
+
+ quarkus-amazon-secretsmanager-config
+ Quarkus - Amazon Services - Secrets Manager Config - Runtime
+ Connect to Amazon Secrets Manager
+
+
+
+ io.quarkiverse.amazonservices
+ quarkus-amazon-common
+
+
+ io.quarkus
+ quarkus-credentials
+
+
+ software.amazon.awssdk
+ secretsmanager
+
+
+ software.amazon.awssdk
+ netty-nio-client
+
+
+ software.amazon.awssdk
+ apache-client
+
+
+
+
+
+
+
+
+ io.quarkus
+ quarkus-extension-maven-plugin
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${quarkus.version}
+
+
+
+
+
+
+
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBuildTimeConfig.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBuildTimeConfig.java
new file mode 100644
index 000000000..24326b3ca
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBuildTimeConfig.java
@@ -0,0 +1,25 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import io.quarkus.amazon.common.runtime.SdkBuildTimeConfig;
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+/**
+ * Amazon Secrets Manager Config build time configuration
+ */
+@ConfigRoot(name = "secretsmanager-config", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
+public class SecretsManagerConfigBuildTimeConfig {
+
+ /**
+ * SDK client configurations for AWS Secrets Manager client
+ */
+ @ConfigItem(name = ConfigItem.PARENT)
+ public SdkBuildTimeConfig sdk;
+
+ /**
+ * Config for dev services
+ */
+ @ConfigItem
+ public SecretsManagerDevServicesBuildTimeConfig devservices;
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigConfig.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigConfig.java
new file mode 100644
index 000000000..c1d41a6ad
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigConfig.java
@@ -0,0 +1,107 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import io.quarkus.amazon.common.runtime.AwsConfig;
+import io.quarkus.amazon.common.runtime.SdkConfig;
+import io.quarkus.amazon.common.runtime.SyncHttpClientConfig;
+import io.quarkus.runtime.annotations.ConfigDocMapKey;
+import io.quarkus.runtime.annotations.ConfigDocSection;
+import io.quarkus.runtime.annotations.ConfigGroup;
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(name = "secretsmanager-config", phase = ConfigPhase.BOOTSTRAP)
+public class SecretsManagerConfigConfig {
+ /**
+ * AWS SDK client configurations
+ */
+ @ConfigItem(name = ConfigItem.PARENT)
+ @ConfigDocSection
+ public SdkConfig sdk;
+
+ /**
+ * AWS services configurations
+ */
+ @ConfigItem
+ @ConfigDocSection
+ public AwsConfig aws;
+
+ /**
+ * Sync HTTP transport configurations
+ */
+ @ConfigItem
+ @ConfigDocSection
+ public SyncHttpClientConfig syncClient;
+
+ /**
+ * Allows you to add filters when listing secrets
+ */
+ @ConfigItem
+ public FilterConfig filter;
+
+ /**
+ * Secrets matching those filter criteria will have their key prefixed
+ */
+ @ConfigItem(name = "filter")
+ @ConfigDocMapKey("prefix")
+ public Map filterPrefix;
+
+ /**
+ * Allows you to add filters when listing secrets
+ */
+ @ConfigGroup
+ public static class FilterConfig {
+
+ /**
+ * enable this filter criterion
+ */
+ @ConfigItem(defaultValue = "true")
+ boolean enabled;
+
+ /**
+ * description: Prefix match, not case-sensitive.
+ */
+ @ConfigItem
+ Optional> description;
+
+ /**
+ * name: Prefix match, case-sensitive.
+ */
+ @ConfigItem
+ Optional> namePrefix;
+
+ /**
+ * tag-key: Prefix match, case-sensitive.
+ */
+ @ConfigItem
+ Optional> tagKey;
+
+ /**
+ * tag-value: Prefix match, case-sensitive.
+ */
+ @ConfigItem
+ Optional> tagValue;
+
+ /**
+ * primary-region: Prefix match, case-sensitive.
+ */
+ @ConfigItem
+ Optional> primaryRegionPrefix;
+
+ /**
+ * owning-service: Prefix match, case-sensitive.
+ */
+ @ConfigItem
+ Optional> owningServicePrefix;
+
+ /**
+ * all
+ */
+ @ConfigItem
+ Optional> all;
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigRecorder.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigRecorder.java
new file mode 100644
index 000000000..43091779c
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigRecorder.java
@@ -0,0 +1,47 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
+
+import io.quarkus.amazon.common.runtime.AwsConfig;
+import io.quarkus.amazon.common.runtime.SdkConfig;
+import io.quarkus.amazon.common.runtime.SyncHttpClientConfig;
+import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.Recorder;
+import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
+import software.amazon.awssdk.http.SdkHttpClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder;
+
+@Recorder
+public class SecretsManagerConfigRecorder {
+
+ public RuntimeValue getSyncConfig(SecretsManagerConfigConfig config) {
+ return new RuntimeValue<>(config.syncClient);
+ }
+
+ public RuntimeValue getAwsConfig(SecretsManagerConfigConfig config) {
+ return new RuntimeValue<>(config.aws);
+ }
+
+ public RuntimeValue getSdkConfig(SecretsManagerConfigConfig config) {
+ return new RuntimeValue<>(config.sdk);
+ }
+
+ public RuntimeValue createSyncBuilder(SecretsManagerConfigConfig config,
+ RuntimeValue transport) {
+ SecretsManagerClientBuilder builder = SecretsManagerClient.builder();
+ if (transport != null) {
+ builder.httpClientBuilder(transport.getValue());
+ }
+ return new RuntimeValue<>(builder);
+ }
+
+ public RuntimeValue configSources(SecretsManagerConfigConfig config,
+ SecretsManagerConfigBuildTimeConfig buildTimeConfig,
+ RuntimeValue syncClientBuilder) {
+
+ return new RuntimeValue<>(
+ new SecretsManagerConfigSourceProvider((SecretsManagerClientBuilder) syncClientBuilder.getValue(),
+ config));
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceProvider.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceProvider.java
new file mode 100644
index 000000000..1a155834b
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceProvider.java
@@ -0,0 +1,122 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import static java.util.stream.Collectors.toMap;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.microprofile.config.spi.ConfigSource;
+import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
+
+import io.smallrye.config.common.MapBackedConfigSource;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder;
+import software.amazon.awssdk.services.secretsmanager.model.Filter;
+import software.amazon.awssdk.services.secretsmanager.model.FilterNameStringType;
+import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
+import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
+import software.amazon.awssdk.services.secretsmanager.model.SecretListEntry;
+
+public class SecretsManagerConfigSourceProvider implements ConfigSourceProvider {
+
+ SecretsManagerClient secretsManagerClient;
+ private SecretsManagerConfigConfig config;
+
+ public SecretsManagerConfigSourceProvider(SecretsManagerClientBuilder syncClientBuilder,
+ SecretsManagerConfigConfig config) {
+ this.config = config;
+ secretsManagerClient = syncClientBuilder.build();
+ }
+
+ @Override
+ public Iterable getConfigSources(ClassLoader forClassLoader) {
+ int ordinal = 299; // one less than env vars
+
+ List result = new ArrayList<>();
+
+ // Retrieve all secrets using pagination and stream
+ Map secretsMap = new HashMap<>();
+ if (config.filter.enabled) {
+ fetchSecrets(secretsMap, config.filter, null);
+ }
+ config.filterPrefix.forEach((t, u) -> {
+ if (u.enabled) {
+ fetchSecrets(secretsMap, u, t);
+ }
+ });
+
+ result.add(new SecretsManagerConfigSource(secretsMap, ordinal));
+
+ return result;
+ }
+
+ private void fetchSecrets(Map properties, SecretsManagerConfigConfig.FilterConfig filters,
+ String prefix) {
+
+ Map secretsMap = secretsManagerClient.listSecretsPaginator(b -> {
+ List requestFilters = new ArrayList<>();
+ filters.namePrefix.ifPresent(namePrefix -> {
+ requestFilters.add(Filter.builder().key(FilterNameStringType.NAME).values(namePrefix).build());
+ });
+
+ filters.primaryRegionPrefix.ifPresent(primaryRegionPrefix -> {
+ requestFilters.add(Filter.builder().key(FilterNameStringType.PRIMARY_REGION)
+ .values(primaryRegionPrefix).build());
+ });
+ filters.owningServicePrefix.ifPresent(owningServicePrefix -> {
+ requestFilters.add(Filter.builder().key(FilterNameStringType.OWNING_SERVICE)
+ .values(owningServicePrefix).build());
+ });
+ filters.tagKey.ifPresent(tagKey -> {
+ requestFilters.add(Filter.builder().key(FilterNameStringType.TAG_KEY).values(tagKey).build());
+ });
+ filters.tagValue.ifPresent(tagValue -> {
+ requestFilters
+ .add(Filter.builder().key(FilterNameStringType.TAG_VALUE).values(tagValue).build());
+ });
+ filters.all.ifPresent(all -> {
+ requestFilters
+ .add(Filter.builder().key(FilterNameStringType.ALL).values(all).build());
+ });
+ filters.description.ifPresent(description -> {
+ requestFilters
+ .add(Filter.builder().key(FilterNameStringType.DESCRIPTION).values(description).build());
+ });
+
+ b.filters(requestFilters);
+ }).stream().flatMap(response -> response.secretList().stream())
+ .collect(Collectors.toUnmodifiableMap(this::getSecretKey,
+ this::getSecretValue));
+
+ properties.putAll(prefixMap(secretsMap, prefix));
+ }
+
+ private String getSecretKey(SecretListEntry secret) {
+ return secret.name();
+ }
+
+ private String getSecretValue(SecretListEntry secret) {
+
+ GetSecretValueRequest getSecretValueRequest = GetSecretValueRequest.builder()
+ .secretId(secret.arn())
+ .build();
+ GetSecretValueResponse getSecretValueResponse = secretsManagerClient.getSecretValue(getSecretValueRequest);
+ return getSecretValueResponse.secretString();
+ }
+
+ private Map prefixMap(Map map, String prefix) {
+ return prefix == null
+ ? map
+ : map.entrySet().stream().collect(toMap(entry -> prefix + "." + entry.getKey(), Map.Entry::getValue));
+ }
+
+ private static final class SecretsManagerConfigSource extends MapBackedConfigSource {
+
+ public SecretsManagerConfigSource(Map propertyMap, int ordinal) {
+ super("SecretsManagerConfigSource", propertyMap, ordinal);
+ }
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerCredentialsProvider.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerCredentialsProvider.java
new file mode 100644
index 000000000..496f6f2bb
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerCredentialsProvider.java
@@ -0,0 +1,24 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.Map;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+
+import io.quarkus.credentials.CredentialsProvider;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+
+@ApplicationScoped
+@Named("secretsmanager-credentials-provider")
+public class SecretsManagerCredentialsProvider implements CredentialsProvider {
+
+ @Inject
+ SecretsManagerClient client;
+
+ @Override
+ public Map getCredentials(String credentialsProviderName) {
+
+ return Map.of();
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerDevServicesBuildTimeConfig.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerDevServicesBuildTimeConfig.java
new file mode 100644
index 000000000..62525a030
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerDevServicesBuildTimeConfig.java
@@ -0,0 +1,17 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.Map;
+
+import io.quarkus.amazon.common.runtime.DevServicesBuildTimeConfig;
+import io.quarkus.runtime.annotations.ConfigGroup;
+import io.quarkus.runtime.annotations.ConfigItem;
+
+@ConfigGroup
+public class SecretsManagerDevServicesBuildTimeConfig extends DevServicesBuildTimeConfig {
+
+ /**
+ * The secrets to create on startup.
+ */
+ @ConfigItem
+ public Map secrets;
+}
diff --git a/secretsmanager-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/secretsmanager-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 000000000..89e9190a3
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,15 @@
+---
+artifact: ${project.groupId}:${project.artifactId}:${project.version}
+name: "Amazon Secrets Manager Config"
+metadata:
+ keywords:
+ - "secretsmanager"
+ - "aws"
+ - "amazon"
+ - "config"
+ categories:
+ - "data"
+ guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-amazon-services/dev/amazon-secretsmanager.html
+ status: "preview"
+ config:
+ - "quarkus.secretsmanager-config."
diff --git a/sns/deployment/pom.xml b/sns/deployment/pom.xml
index d8d7fa24d..02f25960e 100644
--- a/sns/deployment/pom.xml
+++ b/sns/deployment/pom.xml
@@ -44,11 +44,6 @@
rest-assured
test
-
- software.amazon.awssdk
- netty-nio-client
- test
-
software.amazon.awssdk
url-connection-client