diff --git a/bom/pom.xml b/bom/pom.xml
index 36beeae30..9506e7e09 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -172,6 +172,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/pom.xml b/pom.xml
index 70f08ea06..974dd5876 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,6 +29,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..2a1b4673a
--- /dev/null
+++ b/secretsmanager-config/deployment/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 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-devservices-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
+
+
+ software.amazon.awssdk
+ netty-nio-client
+ 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..636aa87a8
--- /dev/null
+++ b/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigProcessor.java
@@ -0,0 +1,185 @@
+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.AmazonClientInterceptorsPathBuildItem;
+import io.quarkus.amazon.common.deployment.AmazonHttpClients;
+import io.quarkus.amazon.common.deployment.RequireAmazonClientBuildItem;
+import io.quarkus.amazon.common.runtime.AbstractAmazonClientTransportRecorder;
+import io.quarkus.amazon.common.runtime.AsyncHttpClientBuildTimeConfig.AsyncClientType;
+import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigBootstrapRecorder;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigBuildTimeConfig;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigSourceAsyncFactoryBuilder;
+import io.quarkus.amazon.secretsmanager.config.runtime.SecretsManagerConfigSourceSyncFactoryBuilder;
+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.ExecutorBuildItem;
+import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem;
+import io.quarkus.runtime.RuntimeValue;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+
+public class SecretsManagerConfigProcessor extends AbstractAmazonServiceProcessor {
+
+ private static final String AMAZON_SECRETS_MANAGER_CONFIG = "amazon-secretsmanager-config";
+
+ private static final DotName SYNC_FACTORY = DotName.createSimple(SecretsManagerConfigSourceSyncFactoryBuilder.class);
+ private static final DotName ASYNC_FACTORY = DotName.createSimple(SecretsManagerConfigSourceAsyncFactoryBuilder.class);
+
+ 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() {
+ return DotName.createSimple(SecretsManagerAsyncClient.class.getName());
+ }
+
+ @Override
+ protected String builtinInterceptorsPath() {
+ return "software/amazon/awssdk/services/secretsmanager/execution.interceptors";
+ }
+
+ @BuildStep
+ void setup(
+ BuildProducer extensionSslNativeSupport,
+ BuildProducer feature,
+ BuildProducer interceptors) {
+
+ setupExtension(extensionSslNativeSupport, feature, interceptors);
+ }
+
+ @BuildStep(onlyIf = AmazonHttpClients.IsAmazonNettyHttpServicePresent.class)
+ @Record(ExecutionTime.STATIC_INIT)
+ public void initBoostrapNettyAsyncTranspor(SecretsManagerConfigBootstrapRecorder recorder,
+ BuildProducer transport,
+ BuildProducer requireClientProducer) {
+
+ if (buildTimeConfig.asyncClient.type != AsyncClientType.NETTY) {
+ return;
+ }
+
+ RuntimeValue transportRecorder = recorder
+ .createNettyTransportRecorder();
+
+ transport.produce(new SecretsManagerConfigTransportBuildItem(Optional.empty(), Optional.of(transportRecorder)));
+ requireClientProducer
+ .produce(new RequireAmazonClientBuildItem(Optional.empty(), Optional.of(asyncClientName())));
+ }
+
+ @BuildStep(onlyIf = AmazonHttpClients.IsAmazonAwsCrtHttpServicePresent.class)
+ @Record(ExecutionTime.STATIC_INIT)
+ public void initBoostrapCrtAsyncTranspor(SecretsManagerConfigBootstrapRecorder recorder,
+ BuildProducer transport,
+ BuildProducer requireClientProducer) {
+
+ if (buildTimeConfig.asyncClient.type != AsyncClientType.AWS_CRT) {
+ return;
+ }
+
+ RuntimeValue transportRecorder = recorder
+ .createAwsCrtTransportRecorder();
+
+ transport.produce(new SecretsManagerConfigTransportBuildItem(Optional.empty(), Optional.of(transportRecorder)));
+ requireClientProducer
+ .produce(new RequireAmazonClientBuildItem(Optional.empty(), Optional.of(asyncClientName())));
+ }
+
+ @BuildStep(onlyIf = AmazonHttpClients.IsAmazonApacheHttpServicePresent.class)
+ @Record(ExecutionTime.STATIC_INIT)
+ public void initBoostrapApacheSyncTransport(SecretsManagerConfigBootstrapRecorder recorder,
+ BuildProducer transport,
+ BuildProducer requireClientProducer) {
+
+ if (buildTimeConfig.syncClient.type != SyncHttpClientBuildTimeConfig.SyncClientType.APACHE) {
+ return;
+ }
+
+ RuntimeValue transportRecorder = recorder
+ .createApacheTransportRecorder();
+
+ transport.produce(new SecretsManagerConfigTransportBuildItem(Optional.of(transportRecorder), Optional.empty()));
+ requireClientProducer
+ .produce(new RequireAmazonClientBuildItem(Optional.of(syncClientName()), Optional.empty()));
+ }
+
+ @BuildStep(onlyIf = AmazonHttpClients.IsAmazonUrlConnectionHttpServicePresent.class)
+ @Record(ExecutionTime.STATIC_INIT)
+ public void initBoostrapUrlConnectionSyncTransport(SecretsManagerConfigBootstrapRecorder recorder,
+ BuildProducer transport,
+ BuildProducer requireClientProducer) {
+
+ if (buildTimeConfig.syncClient.type != SyncHttpClientBuildTimeConfig.SyncClientType.URL) {
+ return;
+ }
+
+ RuntimeValue transportRecorder = recorder
+ .createUrlConnectionTransportRecorder();
+
+ transport.produce(new SecretsManagerConfigTransportBuildItem(Optional.of(transportRecorder), Optional.empty()));
+ requireClientProducer
+ .produce(new RequireAmazonClientBuildItem(Optional.of(syncClientName()), Optional.empty()));
+ }
+
+ @BuildStep
+ @Record(ExecutionTime.STATIC_INIT)
+ public void setupConfigSource(SecretsManagerConfigBootstrapRecorder recorder,
+ List transportRecorders,
+ ExecutorBuildItem executor,
+ BuildProducer runTimeConfigBuilder) {
+
+ if (transportRecorders.isEmpty()) {
+ return;
+ }
+
+ Optional> syncTransportRecorder = Optional.empty();
+ Optional> asyncTransportRecorder = Optional.empty();
+ for (SecretsManagerConfigTransportBuildItem transportRecorder : transportRecorders) {
+
+ if (transportRecorder.getSyncTransporter().isPresent()) {
+ syncTransportRecorder = transportRecorder.getSyncTransporter();
+ }
+ if (transportRecorder.getAsyncTransporter().isPresent()) {
+ asyncTransportRecorder = transportRecorder.getAsyncTransporter();
+ }
+ }
+
+ if (syncTransportRecorder.isPresent() || asyncTransportRecorder.isPresent()) {
+
+ RuntimeValue transportRecorder = syncTransportRecorder
+ .orElse(asyncTransportRecorder.get());
+
+ recorder.configure(transportRecorder, buildTimeConfig.sdk.interceptors);
+
+ if (syncTransportRecorder.isPresent()) {
+ runTimeConfigBuilder
+ .produce(new RunTimeConfigBuilderBuildItem(SYNC_FACTORY.toString()));
+ } else {
+ runTimeConfigBuilder
+ .produce(new RunTimeConfigBuilderBuildItem(ASYNC_FACTORY.toString()));
+ }
+ }
+ }
+}
diff --git a/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigTransportBuildItem.java b/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigTransportBuildItem.java
new file mode 100644
index 000000000..55de1739a
--- /dev/null
+++ b/secretsmanager-config/deployment/src/main/java/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigTransportBuildItem.java
@@ -0,0 +1,27 @@
+package io.quarkus.amazon.secretsmanager.config.deployment;
+
+import java.util.Optional;
+
+import io.quarkus.amazon.common.runtime.AbstractAmazonClientTransportRecorder;
+import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.runtime.RuntimeValue;
+
+public final class SecretsManagerConfigTransportBuildItem extends MultiBuildItem {
+
+ private Optional> syncTransporter;
+ private Optional> asyncTransporter;
+
+ public SecretsManagerConfigTransportBuildItem(Optional> syncTransporter,
+ Optional> asyncTransporter) {
+ this.syncTransporter = syncTransporter;
+ this.asyncTransporter = asyncTransporter;
+ }
+
+ public Optional> getSyncTransporter() {
+ return syncTransporter;
+ }
+
+ public Optional> getAsyncTransporter() {
+ return asyncTransporter;
+ }
+}
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..17ca6d6f9
--- /dev/null
+++ b/secretsmanager-config/deployment/src/test/resources/devservices.properties
@@ -0,0 +1,9 @@
+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
+
+smallrye.config.mapping.validate-unknown=false
\ No newline at end of file
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/SecretsManagerBootstrapHolder.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerBootstrapHolder.java
new file mode 100644
index 000000000..119228832
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerBootstrapHolder.java
@@ -0,0 +1,25 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.List;
+import java.util.Optional;
+
+import io.quarkus.amazon.common.runtime.AbstractAmazonClientTransportRecorder;
+
+final class SecretsManagerBootstrapHolder {
+
+ static AbstractAmazonClientTransportRecorder transportRecorder;
+ static Optional> interceptors;
+
+ static Optional> getInterceptors() {
+ return interceptors;
+ }
+
+ static AbstractAmazonClientTransportRecorder getTransportRecorder() {
+ return transportRecorder;
+ }
+
+ static void setup(AbstractAmazonClientTransportRecorder transportRecorder, Optional> interceptors) {
+ SecretsManagerBootstrapHolder.transportRecorder = transportRecorder;
+ SecretsManagerBootstrapHolder.interceptors = interceptors;
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBootstrapRecorder.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBootstrapRecorder.java
new file mode 100644
index 000000000..571363c99
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBootstrapRecorder.java
@@ -0,0 +1,37 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.List;
+import java.util.Optional;
+
+import io.quarkus.amazon.common.runtime.AbstractAmazonClientTransportRecorder;
+import io.quarkus.amazon.common.runtime.AmazonClientApacheTransportRecorder;
+import io.quarkus.amazon.common.runtime.AmazonClientAwsCrtTransportRecorder;
+import io.quarkus.amazon.common.runtime.AmazonClientNettyTransportRecorder;
+import io.quarkus.amazon.common.runtime.AmazonClientUrlConnectionTransportRecorder;
+import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.Recorder;
+
+@Recorder
+public class SecretsManagerConfigBootstrapRecorder {
+
+ public void configure(RuntimeValue transportRecorder,
+ Optional> interceptors) {
+ SecretsManagerBootstrapHolder.setup(transportRecorder.getValue(), interceptors);
+ }
+
+ public RuntimeValue createUrlConnectionTransportRecorder() {
+ return new RuntimeValue(new AmazonClientUrlConnectionTransportRecorder());
+ }
+
+ public RuntimeValue createApacheTransportRecorder() {
+ return new RuntimeValue(new AmazonClientApacheTransportRecorder());
+ }
+
+ public RuntimeValue createNettyTransportRecorder() {
+ return new RuntimeValue(new AmazonClientNettyTransportRecorder());
+ }
+
+ public RuntimeValue createAwsCrtTransportRecorder() {
+ return new RuntimeValue(new AmazonClientAwsCrtTransportRecorder());
+ }
+}
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..3b62d6dc5
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBuildTimeConfig.java
@@ -0,0 +1,39 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import io.quarkus.amazon.common.runtime.AsyncHttpClientBuildTimeConfig;
+import io.quarkus.amazon.common.runtime.SdkBuildTimeConfig;
+import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig;
+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;
+
+ /**
+ * Sync HTTP transport configuration for Amazon Secrets Manager client
+ */
+ @ConfigItem
+ public SyncHttpClientBuildTimeConfig syncClient;
+
+ /**
+ * Async HTTP transport configuration for Amazon Secrets Manager client
+ */
+ @ConfigItem
+ public AsyncHttpClientBuildTimeConfig asyncClient;
+
+ /**
+ * 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..59524aea9
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigConfig.java
@@ -0,0 +1,108 @@
+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.AsyncHttpClientConfig;
+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.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
+import io.smallrye.config.WithName;
+import io.smallrye.config.WithParentName;
+
+@ConfigMapping(prefix = "quarkus.secretsmanager-config")
+@ConfigRoot(phase = ConfigPhase.RUN_TIME)
+public interface SecretsManagerConfigConfig {
+ /**
+ * AWS SDK client configurations
+ */
+ @WithParentName
+ @ConfigDocSection
+ SdkConfig sdk();
+
+ /**
+ * AWS services configurations
+ */
+ @ConfigDocSection
+ AwsConfig aws();
+
+ /**
+ * Sync HTTP transport configurations
+ */
+ @ConfigDocSection
+ SyncHttpClientConfig syncClient();
+
+ /**
+ * Netty HTTP transport configurations
+ */
+ @ConfigDocSection
+ AsyncHttpClientConfig asyncClient();
+
+ /**
+ * Allows you to add filters when listing secrets
+ */
+ FilterConfig filter();
+
+ /**
+ * Secrets matching those filter criteria will have their key prefixed
+ */
+ @WithName("filter")
+ @ConfigDocMapKey("prefix")
+ public Map filterPrefix();
+
+ /**
+ * Allows you to add filters when listing secrets
+ */
+ @ConfigGroup
+ public interface FilterConfig {
+
+ /**
+ * enable this filter criterion
+ */
+ @WithDefault("true")
+ boolean enabled();
+
+ /**
+ * description: Prefix match, not case-sensitive.
+ */
+ Optional> description();
+
+ /**
+ * name: Prefix match, case-sensitive.
+ */
+ Optional> namePrefix();
+
+ /**
+ * tag-key: Prefix match, case-sensitive.
+ */
+ Optional> tagKey();
+
+ /**
+ * tag-value: Prefix match, case-sensitive.
+ */
+ Optional> tagValue();
+
+ /**
+ * primary-region: Prefix match, case-sensitive.
+ */
+ Optional> primaryRegionPrefix();
+
+ /**
+ * owning-service: Prefix match, case-sensitive.
+ */
+ Optional> owningServicePrefix();
+
+ /**
+ * all
+ */
+ 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..55b86fa95
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigRecorder.java
@@ -0,0 +1,53 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import io.quarkus.amazon.common.runtime.AmazonClientRecorder;
+import io.quarkus.amazon.common.runtime.AsyncHttpClientConfig;
+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.AwsAsyncClientBuilder;
+import software.amazon.awssdk.awscore.client.builder.AwsSyncClientBuilder;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+
+@Recorder
+public class SecretsManagerConfigRecorder extends AmazonClientRecorder {
+
+ final SecretsManagerConfigConfig config;
+
+ public SecretsManagerConfigRecorder(SecretsManagerConfigConfig config) {
+ this.config = config;
+ }
+
+ @Override
+ public RuntimeValue getAwsConfig() {
+ return new RuntimeValue<>(config.aws());
+ }
+
+ @Override
+ public RuntimeValue getSdkConfig() {
+ return new RuntimeValue<>(config.sdk());
+ }
+
+ @Override
+ public AsyncHttpClientConfig getAsyncClientConfig() {
+ return config.asyncClient();
+ }
+
+ @Override
+ public SyncHttpClientConfig getSyncClientConfig() {
+ return config.syncClient();
+ }
+
+ @Override
+ public AwsSyncClientBuilder, ?> geSyncClientBuilder() {
+ return SecretsManagerClient.builder();
+ }
+
+ @Override
+ public AwsAsyncClientBuilder, ?> getAsyncClientBuilder() {
+ return SecretsManagerAsyncClient.builder();
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncFactory.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncFactory.java
new file mode 100644
index 000000000..c3aa8bf18
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncFactory.java
@@ -0,0 +1,51 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.eclipse.microprofile.config.spi.ConfigSource;
+
+import io.quarkus.amazon.common.runtime.AmazonClientCommonRecorder;
+import io.quarkus.amazon.common.runtime.SdkBuildTimeConfig;
+import io.quarkus.runtime.RuntimeValue;
+import io.smallrye.config.ConfigSourceContext;
+import io.smallrye.config.ConfigSourceFactory;
+import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
+import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClientBuilder;
+
+public class SecretsManagerConfigSourceAsyncFactory
+ implements ConfigSourceFactory.ConfigurableConfigSourceFactory {
+
+ private static final int ORDINAL = 270; // this is higher than the file system or jar ordinals, but lower than env vars
+
+ @Override
+ public Iterable getConfigSources(ConfigSourceContext context, SecretsManagerConfigConfig config) {
+
+ var builder = client("amazon-secretsmanager-config", "secretsmanager-config", config);
+
+ var provider = new SecretsManagerConfigSourceAsyncProvider(builder.build(), config, ORDINAL);
+
+ return provider.getConfigSources(SecretsManagerConfigSourceAsyncFactory.class.getClassLoader());
+ }
+
+ private SecretsManagerAsyncClientBuilder client(String clientName, String configName, SecretsManagerConfigConfig config) {
+
+ AmazonClientCommonRecorder clientRecorder = new AmazonClientCommonRecorder();
+ SecretsManagerConfigRecorder secretsManagerConfigRecorder = new SecretsManagerConfigRecorder(config);
+
+ RuntimeValue transportBuilder = SecretsManagerBootstrapHolder.getTransportRecorder()
+ .configureAsync(clientName,
+ new RuntimeValue<>(config.asyncClient()));
+ ScheduledExecutorService executor = null;
+
+ SdkBuildTimeConfig buildTimeConfig = new SdkBuildTimeConfig();
+ buildTimeConfig.interceptors = SecretsManagerBootstrapHolder.getInterceptors();
+
+ RuntimeValue secretsManagerBootstrapClientBuilder = clientRecorder.configure(
+ secretsManagerConfigRecorder.createAsyncBuilder(transportBuilder, executor),
+ secretsManagerConfigRecorder.getAwsConfig(), secretsManagerConfigRecorder.getSdkConfig(),
+ buildTimeConfig, executor, configName);
+
+ return (SecretsManagerAsyncClientBuilder) secretsManagerBootstrapClientBuilder.getValue();
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncFactoryBuilder.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncFactoryBuilder.java
new file mode 100644
index 000000000..d1d5b3863
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncFactoryBuilder.java
@@ -0,0 +1,11 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import io.quarkus.runtime.configuration.ConfigBuilder;
+import io.smallrye.config.SmallRyeConfigBuilder;
+
+public class SecretsManagerConfigSourceAsyncFactoryBuilder implements ConfigBuilder {
+ @Override
+ public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder) {
+ return builder.withSources(new SecretsManagerConfigSourceAsyncFactory());
+ }
+}
\ No newline at end of file
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncProvider.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncProvider.java
new file mode 100644
index 000000000..c8f936775
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncProvider.java
@@ -0,0 +1,37 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClient;
+import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
+import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
+import software.amazon.awssdk.services.secretsmanager.model.ListSecretsRequest.Builder;
+import software.amazon.awssdk.services.secretsmanager.model.SecretListEntry;
+
+public class SecretsManagerConfigSourceAsyncProvider extends SecretsManagerConfigSourceProvider {
+
+ SecretsManagerAsyncClient secretsManagerClient;
+
+ public SecretsManagerConfigSourceAsyncProvider(SecretsManagerAsyncClient secretsManagerAsyncClient,
+ SecretsManagerConfigConfig config,
+ int ordinal) {
+ super(config, ordinal);
+ this.secretsManagerClient = secretsManagerAsyncClient;
+ }
+
+ @Override
+ List listSecretsPaginator(Consumer listSecretsRequestBuilder) {
+ List result = new ArrayList<>();
+ secretsManagerClient.listSecretsPaginator(listSecretsRequestBuilder).subscribe(c -> result.addAll(c.secretList()))
+ .join();
+
+ return result;
+ }
+
+ @Override
+ GetSecretValueResponse getSecretValue(Consumer getSecretValueRequestBuilder) {
+ return secretsManagerClient.getSecretValue(getSecretValueRequestBuilder).join();
+ }
+}
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..b2829c7f0
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceProvider.java
@@ -0,0 +1,121 @@
+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.function.Consumer;
+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.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.ListSecretsRequest;
+import software.amazon.awssdk.services.secretsmanager.model.SecretListEntry;
+
+public abstract class SecretsManagerConfigSourceProvider implements ConfigSourceProvider {
+
+ private SecretsManagerConfigConfig config;
+ private int ordinal;
+
+ public SecretsManagerConfigSourceProvider(
+ SecretsManagerConfigConfig config,
+ int ordinal) {
+ this.config = config;
+ this.ordinal = ordinal;
+ }
+
+ @Override
+ public Iterable getConfigSources(ClassLoader forClassLoader) {
+ 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;
+ }
+
+ abstract List listSecretsPaginator(Consumer listSecretsRequestBuilder);
+
+ abstract GetSecretValueResponse getSecretValue(
+ Consumer getSecretValueRequestBuilder);
+
+ private void fetchSecrets(Map properties, SecretsManagerConfigConfig.FilterConfig filters,
+ String prefix) {
+
+ Map secretsMap = 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()
+ .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) {
+ return getSecretValue(b -> b.secretId(secret.arn())).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/SecretsManagerConfigSourceSyncFactory.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncFactory.java
new file mode 100644
index 000000000..23c7b5afc
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncFactory.java
@@ -0,0 +1,51 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.eclipse.microprofile.config.spi.ConfigSource;
+
+import io.quarkus.amazon.common.runtime.AmazonClientCommonRecorder;
+import io.quarkus.amazon.common.runtime.SdkBuildTimeConfig;
+import io.quarkus.runtime.RuntimeValue;
+import io.smallrye.config.ConfigSourceContext;
+import io.smallrye.config.ConfigSourceFactory;
+import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
+import software.amazon.awssdk.http.SdkHttpClient;
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder;
+
+public class SecretsManagerConfigSourceSyncFactory
+ implements ConfigSourceFactory.ConfigurableConfigSourceFactory {
+
+ private static final int ORDINAL = 270; // this is higher than the file system or jar ordinals, but lower than env vars
+
+ @Override
+ public Iterable getConfigSources(ConfigSourceContext context, SecretsManagerConfigConfig config) {
+
+ var builder = client("amazon-secretsmanager-config", "secretsmanager-config", config);
+
+ var provider = new SecretsManagerConfigSourceSyncProvider(builder.build(), config, ORDINAL);
+
+ return provider.getConfigSources(SecretsManagerConfigSourceSyncFactory.class.getClassLoader());
+ }
+
+ private SecretsManagerClientBuilder client(String clientName, String configName, SecretsManagerConfigConfig config) {
+
+ AmazonClientCommonRecorder clientRecorder = new AmazonClientCommonRecorder();
+ SecretsManagerConfigRecorder secretsManagerConfigRecorder = new SecretsManagerConfigRecorder(config);
+
+ RuntimeValue transportBuilder = SecretsManagerBootstrapHolder.getTransportRecorder()
+ .configureSync(clientName,
+ new RuntimeValue<>(config.syncClient()));
+ ScheduledExecutorService executor = null;
+
+ SdkBuildTimeConfig buildTimeConfig = new SdkBuildTimeConfig();
+ buildTimeConfig.interceptors = SecretsManagerBootstrapHolder.getInterceptors();
+
+ RuntimeValue secretsManagerBootstrapClientBuilder = clientRecorder.configure(
+ secretsManagerConfigRecorder.createSyncBuilder(transportBuilder),
+ secretsManagerConfigRecorder.getAwsConfig(), secretsManagerConfigRecorder.getSdkConfig(),
+ buildTimeConfig, executor, configName);
+
+ return (SecretsManagerClientBuilder) secretsManagerBootstrapClientBuilder.getValue();
+ }
+}
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncFactoryBuilder.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncFactoryBuilder.java
new file mode 100644
index 000000000..5cbfe22c1
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncFactoryBuilder.java
@@ -0,0 +1,11 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import io.quarkus.runtime.configuration.ConfigBuilder;
+import io.smallrye.config.SmallRyeConfigBuilder;
+
+public class SecretsManagerConfigSourceSyncFactoryBuilder implements ConfigBuilder {
+ @Override
+ public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder) {
+ return builder.withSources(new SecretsManagerConfigSourceSyncFactory());
+ }
+}
\ No newline at end of file
diff --git a/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncProvider.java b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncProvider.java
new file mode 100644
index 000000000..1621f41f4
--- /dev/null
+++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncProvider.java
@@ -0,0 +1,35 @@
+package io.quarkus.amazon.secretsmanager.config.runtime;
+
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
+import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
+import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
+import software.amazon.awssdk.services.secretsmanager.model.ListSecretsRequest;
+import software.amazon.awssdk.services.secretsmanager.model.SecretListEntry;
+
+public class SecretsManagerConfigSourceSyncProvider extends SecretsManagerConfigSourceProvider {
+
+ SecretsManagerClient secretsManagerClient;
+
+ public SecretsManagerConfigSourceSyncProvider(SecretsManagerClient syncClientBuilder,
+ SecretsManagerConfigConfig config,
+ int ordinal) {
+ super(config, ordinal);
+ this.secretsManagerClient = syncClientBuilder;
+ }
+
+ @Override
+ List listSecretsPaginator(Consumer listSecretsRequestBuilder) {
+ return secretsManagerClient.listSecretsPaginator(listSecretsRequestBuilder).stream()
+ .flatMap(response -> response.secretList().stream())
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ GetSecretValueResponse getSecretValue(Consumer getSecretValueRequestBuilder) {
+ return secretsManagerClient.getSecretValue(getSecretValueRequestBuilder);
+ }
+}
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."