Skip to content

Commit

Permalink
Wire SecretsSuppliers up to Quarkus
Browse files Browse the repository at this point in the history
  • Loading branch information
snazy committed Jun 26, 2024
1 parent 1b567f2 commit e645d56
Show file tree
Hide file tree
Showing 24 changed files with 1,160 additions and 4 deletions.
10 changes: 10 additions & 0 deletions servers/quarkus-common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ dependencies {
implementation(project(":nessie-catalog-files-impl"))
implementation(project(":nessie-catalog-service-common"))
implementation(project(":nessie-catalog-secrets-api"))
implementation(project(":nessie-catalog-secrets-cache"))
implementation(project(":nessie-catalog-secrets-aws"))
implementation(project(":nessie-catalog-secrets-gcs"))
implementation(project(":nessie-catalog-secrets-vault"))

compileOnly(project(":nessie-doc-generator-annotations"))

Expand All @@ -55,14 +59,20 @@ dependencies {
implementation("io.quarkus:quarkus-opentelemetry")
implementation("io.quarkus:quarkus-micrometer")
implementation("io.smallrye.config:smallrye-config-source-keystore")

implementation(enforcedPlatform(libs.quarkus.amazon.services.bom))
implementation("io.quarkiverse.amazonservices:quarkus-amazon-secretsmanager")
implementation("io.quarkiverse.amazonservices:quarkus-amazon-dynamodb")
implementation("software.amazon.awssdk:sts")
implementation("software.amazon.awssdk:apache-client") {
exclude("commons-logging", "commons-logging")
}
implementation(enforcedPlatform(libs.quarkus.google.cloud.services.bom))
implementation("io.quarkiverse.googlecloudservices:quarkus-google-cloud-secret-manager")
implementation("io.quarkiverse.googlecloudservices:quarkus-google-cloud-bigtable")

implementation("io.quarkiverse.vault:quarkus-vault")

implementation(enforcedPlatform(libs.quarkus.cassandra.bom))
implementation("com.datastax.oss.quarkus:cassandra-quarkus-client") {
// spotbugs-annotations has only a GPL license!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.config;

import io.smallrye.config.WithDefault;
import java.time.Duration;
import java.util.OptionalLong;

/** Configurations for secrets caching. */
public interface QuarkusSecretsCacheConfig {
/** Flag whether the secrets cache is enabled. */
@WithDefault("true")
boolean enabled();

/** Optionally restrict the number of cached secrets. */
OptionalLong maxElements();

/** Approximated maximum size on the Java heap for cached secrets. */
@WithDefault("16")
long capacityMb();

/** Time until cached secrets expire. */
@WithDefault("PT15M")
Duration ttl();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.config;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

@ConfigMapping(prefix = "nessie.secrets")
public interface QuarkusSecretsConfig {
/** Choose the secrets manager to use. */
@WithDefault("NONE")
SecretsSupplierType type();

@WithDefault("nessie/secrets")
String path();

QuarkusSecretsCacheConfig cache();

enum SecretsSupplierType {
NONE,
VAULT,
GOOGLE,
AMAZON
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.providers.secrets;

import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
import org.projectnessie.catalog.secrets.aws.AwsSecretsSupplier;
import org.projectnessie.catalog.secrets.spi.SecretsSupplier;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig.SecretsSupplierType;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;

@Dependent
@SecretsType(SecretsSupplierType.AMAZON)
public class AmazonSecretsSupplierBuilder implements SecretsSupplierBuilder {
@Inject SecretsManagerClient client;

@Inject QuarkusSecretsConfig secretsConfig;

@Override
public SecretsSupplier buildSupplier() {
String prefix = secretsConfig.path();
if (!prefix.isEmpty()) {
prefix += ".";
}
return new AwsSecretsSupplier(client, prefix);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.providers.secrets;

import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
import org.projectnessie.catalog.secrets.gcs.GcsSecretsSupplier;
import org.projectnessie.catalog.secrets.spi.SecretsSupplier;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig.SecretsSupplierType;

@Dependent
@SecretsType(SecretsSupplierType.GOOGLE)
public class GoogleSecretsSupplierBuilder implements SecretsSupplierBuilder {

@Inject SecretManagerServiceClient client;

@Inject QuarkusSecretsConfig secretsConfig;

@Override
public SecretsSupplier buildSupplier() {
String prefix = secretsConfig.path();
if (!prefix.isEmpty()) {
prefix += ".";
}
return new GcsSecretsSupplier(client, prefix);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.providers.secrets;

import jakarta.enterprise.context.Dependent;
import java.util.Map;
import org.projectnessie.catalog.secrets.spi.SecretsSupplier;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig.SecretsSupplierType;

@Dependent
@SecretsType(SecretsSupplierType.NONE)
public class NoneSecretsSupplierBuilder implements SecretsSupplierBuilder {
@Override
public SecretsSupplier buildSupplier() {
return names -> Map.of();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.providers.secrets;

import org.projectnessie.catalog.secrets.spi.SecretsSupplier;

public interface SecretsSupplierBuilder {
SecretsSupplier buildSupplier();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.providers.secrets;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import jakarta.enterprise.util.AnnotationLiteral;
import jakarta.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig.SecretsSupplierType;

/** Store type qualifier for {@code VersionStoreFactory} classes. */
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface SecretsType {
/** Gets the store type. */
SecretsSupplierType value();

/** Supports inline instantiation of the {@link SecretsType} qualifier. */
final class Literal extends AnnotationLiteral<SecretsType> implements SecretsType {

private static final long serialVersionUID = 1L;
private final SecretsSupplierType value;

public Literal(SecretsSupplierType value) {
this.value = value;
}

@Override
public SecretsSupplierType value() {
return value;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.quarkus.providers.secrets;

import io.quarkus.vault.VaultKVSecretReactiveEngine;
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
import org.projectnessie.catalog.secrets.spi.SecretsSupplier;
import org.projectnessie.catalog.secrets.vault.VaultSecretsSupplier;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig;
import org.projectnessie.quarkus.config.QuarkusSecretsConfig.SecretsSupplierType;

@Dependent
@SecretsType(SecretsSupplierType.VAULT)
public class VaultSecretsSupplierBuilder implements SecretsSupplierBuilder {
@Inject VaultKVSecretReactiveEngine engine;

@Inject QuarkusSecretsConfig secretsConfig;

@Override
public SecretsSupplier buildSupplier() {
return new VaultSecretsSupplier(engine, secretsConfig.path() + "/");
}
}
13 changes: 13 additions & 0 deletions servers/quarkus-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ dependencies {
implementation(project(":nessie-catalog-service-impl"))
implementation(project(":nessie-catalog-service-rest"))
implementation(project(":nessie-catalog-secrets-api"))
implementation(project(":nessie-catalog-secrets-cache"))
implementation(libs.nessie.ui)

implementation(enforcedPlatform(libs.quarkus.bom))
Expand Down Expand Up @@ -150,13 +151,20 @@ dependencies {

testFixturesApi(platform(libs.testcontainers.bom))
testFixturesApi("org.testcontainers:testcontainers")
testFixturesApi("org.testcontainers:localstack")
testFixturesApi("org.testcontainers:vault")
testFixturesApi(project(":nessie-keycloak-testcontainer"))
testFixturesApi(project(":nessie-azurite-testcontainer"))
testFixturesApi(project(":nessie-gcs-testcontainer"))
testFixturesApi(project(":nessie-minio-testcontainer"))
testFixturesApi(project(":nessie-object-storage-mock"))
testFixturesApi(project(":nessie-catalog-format-iceberg"))
testFixturesApi(project(":nessie-catalog-format-iceberg-fixturegen"))
testFixturesApi(project(":nessie-container-spec-helper"))

testFixturesApi(platform(libs.awssdk.bom))
testFixturesApi("software.amazon.awssdk:secretsmanager")
testFixturesApi("io.quarkiverse.vault:quarkus-vault-deployment")

testFixturesApi(platform("org.apache.iceberg:iceberg-bom:$versionIceberg"))
testFixturesApi("org.apache.iceberg:iceberg-core")
Expand All @@ -170,12 +178,17 @@ dependencies {

testFixturesCompileOnly(libs.microprofile.openapi)

testCompileOnly(project(":nessie-immutables"))
testAnnotationProcessor(project(":nessie-immutables", configuration = "processor"))

intTestImplementation("io.quarkus:quarkus-test-keycloak-server")
intTestImplementation(project(":nessie-keycloak-testcontainer"))

intTestImplementation(platform(libs.awssdk.bom))
intTestImplementation("software.amazon.awssdk:s3")
intTestImplementation("software.amazon.awssdk:sts")

intTestCompileOnly(libs.immutables.value.annotations)
}

val pullOpenApiSpec by tasks.registering(Sync::class)
Expand Down
Loading

0 comments on commit e645d56

Please sign in to comment.