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 c401042c6..3958b2361 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..1feca8bd3 --- /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..96f93b57d --- /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..4dba763ce --- /dev/null +++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigBuildTimeConfig.java @@ -0,0 +1,31 @@ +package io.quarkus.amazon.secretsmanager.config.runtime; + +import io.quarkus.amazon.common.runtime.AsyncHttpClientBuildTimeConfig; +import io.quarkus.amazon.common.runtime.HasSdkBuildTimeConfig; +import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; + +/** + * Amazon Secrets Manager Config build time configuration + */ +@ConfigMapping(prefix = "quarkus.secretsmanager-config") +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +public interface SecretsManagerConfigBuildTimeConfig extends HasSdkBuildTimeConfig { + + /** + * Sync HTTP transport configuration for Amazon Secrets Manager client + */ + SyncHttpClientBuildTimeConfig syncClient(); + + /** + * Async HTTP transport configuration for Amazon Secrets Manager client + */ + AsyncHttpClientBuildTimeConfig asyncClient(); + + /** + * Config for dev services + */ + 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..767e7f516 --- /dev/null +++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceAsyncFactory.java @@ -0,0 +1,81 @@ +package io.quarkus.amazon.secretsmanager.config.runtime; + +import java.util.List; +import java.util.Optional; +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.AsyncHttpClientBuildTimeConfig; +import io.quarkus.amazon.common.runtime.SdkBuildTimeConfig; +import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig; +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; + + SecretsManagerConfigBuildTimeConfig buildTimeConfig = new SecretsManagerConfigBuildTimeConfig() { + + @Override + public SdkBuildTimeConfig sdk() { + return new SdkBuildTimeConfig() { + + @Override + public Optional> interceptors() { + return SecretsManagerBootstrapHolder.getInterceptors(); + } + }; + } + + @Override + public SyncHttpClientBuildTimeConfig syncClient() { + throw new UnsupportedOperationException("Unimplemented method 'syncClient'"); + } + + @Override + public AsyncHttpClientBuildTimeConfig asyncClient() { + throw new UnsupportedOperationException("Unimplemented method 'asyncClient'"); + } + + @Override + public SecretsManagerDevServicesBuildTimeConfig devservices() { + throw new UnsupportedOperationException("Unimplemented method 'devservices'"); + } + }; + + 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..5877810ed --- /dev/null +++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerConfigSourceSyncFactory.java @@ -0,0 +1,81 @@ +package io.quarkus.amazon.secretsmanager.config.runtime; + +import java.util.List; +import java.util.Optional; +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.AsyncHttpClientBuildTimeConfig; +import io.quarkus.amazon.common.runtime.SdkBuildTimeConfig; +import io.quarkus.amazon.common.runtime.SyncHttpClientBuildTimeConfig; +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; + + SecretsManagerConfigBuildTimeConfig buildTimeConfig = new SecretsManagerConfigBuildTimeConfig() { + + @Override + public SdkBuildTimeConfig sdk() { + return new SdkBuildTimeConfig() { + + @Override + public Optional> interceptors() { + return SecretsManagerBootstrapHolder.getInterceptors(); + } + }; + } + + @Override + public SyncHttpClientBuildTimeConfig syncClient() { + throw new UnsupportedOperationException("Unimplemented method 'syncClient'"); + } + + @Override + public AsyncHttpClientBuildTimeConfig asyncClient() { + throw new UnsupportedOperationException("Unimplemented method 'asyncClient'"); + } + + @Override + public SecretsManagerDevServicesBuildTimeConfig devservices() { + throw new UnsupportedOperationException("Unimplemented method 'devservices'"); + } + }; + + 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..92e3625c0 --- /dev/null +++ b/secretsmanager-config/runtime/src/main/java/io/quarkus/amazon/secretsmanager/config/runtime/SecretsManagerDevServicesBuildTimeConfig.java @@ -0,0 +1,15 @@ +package io.quarkus.amazon.secretsmanager.config.runtime; + +import java.util.Map; + +import io.quarkus.amazon.common.runtime.DevServicesBuildTimeConfig; +import io.quarkus.runtime.annotations.ConfigGroup; + +@ConfigGroup +public interface SecretsManagerDevServicesBuildTimeConfig extends DevServicesBuildTimeConfig { + + /** + * The secrets to create on startup. + */ + 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."