-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for reading configuration from a Secrets Manager
- Loading branch information
1 parent
873b695
commit 1735c29
Showing
25 changed files
with
1,112 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>io.quarkiverse.amazonservices</groupId> | ||
<artifactId>quarkus-amazon-secretsmanager-config-parent</artifactId> | ||
<version>999-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>quarkus-amazon-secretsmanager-config-deployment</artifactId> | ||
<name>Quarkus - Amazon Services - Secrets Manager Config - Deployment</name> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.quarkiverse.amazonservices</groupId> | ||
<artifactId>quarkus-amazon-common-deployment</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.quarkiverse.amazonservices</groupId> | ||
<artifactId>quarkus-amazon-common-deployment-devservices-spi</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-credentials-deployment</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.quarkiverse.amazonservices</groupId> | ||
<artifactId>quarkus-amazon-secretsmanager-config</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>software.amazon.awssdk</groupId> | ||
<artifactId>url-connection-client</artifactId> | ||
</dependency> | ||
|
||
<!-- Test dependencies --> | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-junit5-internal</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.rest-assured</groupId> | ||
<artifactId>rest-assured</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>software.amazon.awssdk</groupId> | ||
<artifactId>netty-nio-client</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<configuration> | ||
<annotationProcessorPaths> | ||
<path> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-extension-processor</artifactId> | ||
<version>${quarkus.version}</version> | ||
</path> | ||
</annotationProcessorPaths> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
54 changes: 54 additions & 0 deletions
54
...kus/amazon/secretsmanager/config/deployment/SecretsManagerConfigDevServicesProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String, String> 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)); | ||
}); | ||
} | ||
} | ||
} |
185 changes: 185 additions & 0 deletions
185
...ava/io/quarkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ExtensionSslNativeSupportBuildItem> extensionSslNativeSupport, | ||
BuildProducer<FeatureBuildItem> feature, | ||
BuildProducer<AmazonClientInterceptorsPathBuildItem> interceptors) { | ||
|
||
setupExtension(extensionSslNativeSupport, feature, interceptors); | ||
} | ||
|
||
@BuildStep(onlyIf = AmazonHttpClients.IsAmazonNettyHttpServicePresent.class) | ||
@Record(ExecutionTime.STATIC_INIT) | ||
public void initBoostrapNettyAsyncTranspor(SecretsManagerConfigBootstrapRecorder recorder, | ||
BuildProducer<SecretsManagerConfigTransportBuildItem> transport, | ||
BuildProducer<RequireAmazonClientBuildItem> requireClientProducer) { | ||
|
||
if (buildTimeConfig.asyncClient.type != AsyncClientType.NETTY) { | ||
return; | ||
} | ||
|
||
RuntimeValue<AbstractAmazonClientTransportRecorder> 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<SecretsManagerConfigTransportBuildItem> transport, | ||
BuildProducer<RequireAmazonClientBuildItem> requireClientProducer) { | ||
|
||
if (buildTimeConfig.asyncClient.type != AsyncClientType.AWS_CRT) { | ||
return; | ||
} | ||
|
||
RuntimeValue<AbstractAmazonClientTransportRecorder> 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<SecretsManagerConfigTransportBuildItem> transport, | ||
BuildProducer<RequireAmazonClientBuildItem> requireClientProducer) { | ||
|
||
if (buildTimeConfig.syncClient.type != SyncHttpClientBuildTimeConfig.SyncClientType.APACHE) { | ||
return; | ||
} | ||
|
||
RuntimeValue<AbstractAmazonClientTransportRecorder> 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<SecretsManagerConfigTransportBuildItem> transport, | ||
BuildProducer<RequireAmazonClientBuildItem> requireClientProducer) { | ||
|
||
if (buildTimeConfig.syncClient.type != SyncHttpClientBuildTimeConfig.SyncClientType.URL) { | ||
return; | ||
} | ||
|
||
RuntimeValue<AbstractAmazonClientTransportRecorder> 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<SecretsManagerConfigTransportBuildItem> transportRecorders, | ||
ExecutorBuildItem executor, | ||
BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) { | ||
|
||
if (transportRecorders.isEmpty()) { | ||
return; | ||
} | ||
|
||
Optional<RuntimeValue<AbstractAmazonClientTransportRecorder>> syncTransportRecorder = Optional.empty(); | ||
Optional<RuntimeValue<AbstractAmazonClientTransportRecorder>> 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<AbstractAmazonClientTransportRecorder> 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())); | ||
} | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...arkus/amazon/secretsmanager/config/deployment/SecretsManagerConfigTransportBuildItem.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<RuntimeValue<AbstractAmazonClientTransportRecorder>> syncTransporter; | ||
private Optional<RuntimeValue<AbstractAmazonClientTransportRecorder>> asyncTransporter; | ||
|
||
public SecretsManagerConfigTransportBuildItem(Optional<RuntimeValue<AbstractAmazonClientTransportRecorder>> syncTransporter, | ||
Optional<RuntimeValue<AbstractAmazonClientTransportRecorder>> asyncTransporter) { | ||
this.syncTransporter = syncTransporter; | ||
this.asyncTransporter = asyncTransporter; | ||
} | ||
|
||
public Optional<RuntimeValue<AbstractAmazonClientTransportRecorder>> getSyncTransporter() { | ||
return syncTransporter; | ||
} | ||
|
||
public Optional<RuntimeValue<AbstractAmazonClientTransportRecorder>> getAsyncTransporter() { | ||
return asyncTransporter; | ||
} | ||
} |
Oops, something went wrong.