diff --git a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultITCase.java b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultITCase.java index 2a2c8813..e7e6827e 100644 --- a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultITCase.java +++ b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultITCase.java @@ -62,7 +62,9 @@ import io.quarkus.vault.runtime.client.dto.auth.VaultRenewSelf; import io.quarkus.vault.runtime.client.dto.auth.VaultUserPassAuth; import io.quarkus.vault.runtime.client.dto.dynamic.VaultDynamicCredentials; -import io.quarkus.vault.runtime.client.dto.kv.*; +import io.quarkus.vault.runtime.client.dto.kv.VaultKvListSecrets; +import io.quarkus.vault.runtime.client.dto.kv.VaultKvSecretJsonV1; +import io.quarkus.vault.runtime.client.dto.kv.VaultKvSecretJsonV2; import io.quarkus.vault.runtime.client.dto.sys.VaultLeasesLookup; import io.quarkus.vault.runtime.client.dto.sys.VaultRenewLease; import io.quarkus.vault.runtime.client.dto.sys.VaultWrapResult; diff --git a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultProxyITCase.java b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultProxyITCase.java index 099520a7..68adcee3 100644 --- a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultProxyITCase.java +++ b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultProxyITCase.java @@ -2,7 +2,7 @@ import static io.quarkus.vault.WiremockProxy.PROXY_HOST; import static io.quarkus.vault.WiremockProxy.PROXY_PORT; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import jakarta.inject.Inject; diff --git a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultSysITCase.java b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultSysITCase.java index 645367cd..c2bf38fa 100644 --- a/integration-tests/vault/src/test/java/io/quarkus/vault/VaultSysITCase.java +++ b/integration-tests/vault/src/test/java/io/quarkus/vault/VaultSysITCase.java @@ -2,20 +2,24 @@ import static io.quarkus.vault.test.VaultTestExtension.SECRET_PATH_V1; import static io.quarkus.vault.test.VaultTestExtension.SECRET_PATH_V2; +import static org.apache.commons.codec.digest.DigestUtils.sha256Hex; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; +import java.util.Map; import java.util.Random; import jakarta.inject.Inject; import org.jboss.logging.Logger; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -25,10 +29,12 @@ import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.vault.runtime.client.VaultClientException; import io.quarkus.vault.sys.EnableEngineOptions; +import io.quarkus.vault.sys.EngineListingVisibility; import io.quarkus.vault.sys.VaultSealStatus; import io.quarkus.vault.sys.VaultSecretEngine; import io.quarkus.vault.sys.VaultSecretEngineInfo; import io.quarkus.vault.sys.VaultTuneInfo; +import io.quarkus.vault.test.VaultTestExtension; import io.quarkus.vault.test.VaultTestLifecycleManager; @DisabledOnOs(OS.WINDOWS) // https://github.com/quarkusio/quarkus/issues/3796 @@ -47,6 +53,13 @@ public class VaultSysITCase { @Inject VaultSystemBackendEngine vaultSystemBackendEngine; + @BeforeEach + void setup() { + // Unregister any test plugins that may have been registered by previous tests + vaultSystemBackendEngine.removePlugin("secret", "test-plugin", null); + vaultSystemBackendEngine.removePlugin("secret", "test-plugin", "v0.0.1"); + } + @Test public void testSealStatus() { final VaultSealStatus vaultSealStatus = vaultSystemBackendEngine.sealStatus(); @@ -102,7 +115,7 @@ public void testSecretEngineInfo() { // v1 info = vaultSystemBackendEngine.getSecretEngineInfo(SECRET_PATH_V1); Assertions.assertEquals(VaultSecretEngine.KEY_VALUE.getType(), info.getType()); - Assertions.assertNull(info.getOptions()); + assertNull(info.getOptions()); } @Test @@ -142,4 +155,237 @@ public void testEnableDisable() { assertFalse(vaultSystemBackendEngine.isEngineMounted(randomMount)); } + @Test + public void testEnableAdvancedOptions() throws Exception { + + String randomMount = String.format("test-%X", RANDOM.nextInt()); + + assertFalse(vaultSystemBackendEngine.isEngineMounted(randomMount)); + + EnableEngineOptions options = new EnableEngineOptions() + .setOptions(Map.of("version", "2")) + .setAllowedManagedKeys(List.of("key1")) + .setAuditNonHMACRequestKeys(List.of("key2")) + .setAuditNonHMACResponseKeys(List.of("key3")) + .setAllowedResponseHeaders(List.of("header1")) + .setPassthroughRequestHeaders(List.of("header2")) + .setListingVisibility(EngineListingVisibility.UNAUTH) + .setDefaultLeaseTimeToLive("1h") + .setMaxLeaseTimeToLive("24h") + .setForceNoCache(true); + + assertDoesNotThrow( + () -> vaultSystemBackendEngine.enable("kv", randomMount, "KV with crazy options", options)); + + var info = vaultSystemBackendEngine.getSecretEngineInfo(randomMount); + assertEquals(List.of("key1"), info.getAllowedManagedKeys()); + assertEquals(List.of("key2"), info.getAuditNonHMACRequestKeys()); + assertEquals(List.of("key3"), info.getAuditNonHMACResponseKeys()); + assertEquals(List.of("header1"), info.getAllowedResponseHeaders()); + assertEquals(List.of("header2"), info.getPassthroughRequestHeaders()); + assertEquals(EngineListingVisibility.UNAUTH, info.getListingVisibility()); + assertEquals(3600, info.getDefaultLeaseTimeToLive()); + assertEquals(86400, info.getMaxLeaseTimeToLive()); + assertTrue(info.getForceNoCache()); + assertEquals("{version=2}", info.getOptions().toString()); + + var tuneInfo = vaultSystemBackendEngine.getTuneInfo(randomMount); + assertEquals(List.of("key1"), tuneInfo.getAllowedManagedKeys()); + assertEquals(List.of("key2"), tuneInfo.getAuditNonHMACRequestKeys()); + assertEquals(List.of("key3"), tuneInfo.getAuditNonHMACResponseKeys()); + assertEquals(List.of("header1"), tuneInfo.getAllowedResponseHeaders()); + assertEquals(List.of("header2"), tuneInfo.getPassthroughRequestHeaders()); + assertEquals(EngineListingVisibility.UNAUTH, tuneInfo.getListingVisibility()); + assertEquals(3600, tuneInfo.getDefaultLeaseTimeToLive()); + assertEquals(86400, tuneInfo.getMaxLeaseTimeToLive()); + assertTrue(tuneInfo.getForceNoCache()); + assertEquals("{version=2}", tuneInfo.getOptions().toString()); + } + + @Test + public void testEnableDisableCustomPluginWithoutVersion() throws Exception { + registerTestPlugin(false); + + String randomMount = String.format("test-%X", RANDOM.nextInt()); + + assertFalse(vaultSystemBackendEngine.isEngineMounted(randomMount)); + + EnableEngineOptions options = new EnableEngineOptions() + .setPluginVersion(null); + + assertDoesNotThrow( + () -> vaultSystemBackendEngine.enable("test-plugin", randomMount, "Test plugin engine", options)); + + var info = vaultSystemBackendEngine.getSecretEngineInfo(randomMount); + assertEquals("", info.getPluginVersion()); + + assertDoesNotThrow(() -> vaultSystemBackendEngine.disable(randomMount)); + + assertFalse(vaultSystemBackendEngine.isEngineMounted(randomMount)); + } + + @Test + public void testEnableDisableCustomPluginWithVersion() throws Exception { + registerTestPlugin(true); + + String randomMount = String.format("test-%X", RANDOM.nextInt()); + + assertFalse(vaultSystemBackendEngine.isEngineMounted(randomMount)); + + EnableEngineOptions options = new EnableEngineOptions() + .setPluginVersion("v0.0.1"); + + assertDoesNotThrow( + () -> vaultSystemBackendEngine.enable("test-plugin", randomMount, "Test plugin engine", options)); + + assertTrue(vaultSystemBackendEngine.isEngineMounted(randomMount)); + + assertDoesNotThrow(() -> vaultSystemBackendEngine.disable(randomMount)); + + assertFalse(vaultSystemBackendEngine.isEngineMounted(randomMount)); + } + + @Test + public void testListPlugins() throws Exception { + var testPluginSHA = registerTestPlugin(true); + + var plugins = vaultSystemBackendEngine.listPlugins(); + assertNotNull(plugins); + assertNotNull(plugins.getAuth()); + assertNotNull(plugins.getDatabase()); + assertNotNull(plugins.getSecret()); + assertNotNull(plugins.getDetailed()); + + assertTrue(plugins.getAuth().contains("userpass")); + assertTrue(plugins.getDatabase().contains("mysql-database-plugin")); + assertTrue(plugins.getSecret().contains("kv")); + + // Check builtin plugin details + var kvDetails = plugins.getDetailed().stream().filter(p -> p.getName().equals("kv")).findFirst().orElse(null); + assertNotNull(kvDetails); + assertEquals(true, kvDetails.getBuiltin()); + assertEquals("supported", kvDetails.getDeprecationStatus()); + assertEquals("kv", kvDetails.getName()); + assertEquals("secret", kvDetails.getType()); + assertTrue(kvDetails.getVersion().matches("v[0-9]+\\.[0-9]+\\.[0-9]+\\+builtin")); + assertNull(kvDetails.getSha256()); + assertNull(kvDetails.getCommand()); + assertNull(kvDetails.getArgs()); + assertNull(kvDetails.getEnv()); + + // Check custom plugin details + var testPluginDetails = plugins.getDetailed().stream().filter(p -> p.getName().equals("test-plugin")).findFirst() + .orElse(null); + assertNotNull(testPluginDetails); + assertEquals(false, testPluginDetails.getBuiltin()); + assertNull(testPluginDetails.getDeprecationStatus()); + assertEquals("test-plugin", testPluginDetails.getName()); + assertEquals("secret", testPluginDetails.getType()); + assertEquals("v0.0.1", testPluginDetails.getVersion()); + assertEquals(testPluginSHA, testPluginDetails.getSha256()); + assertNull(testPluginDetails.getCommand()); + assertNull(testPluginDetails.getArgs()); + assertNull(testPluginDetails.getEnv()); + } + + @Test + void testListPluginsOfType() { + var plugins = vaultSystemBackendEngine.listPlugins("secret"); + assertNotNull(plugins); + assertTrue(plugins.contains("kv")); + assertFalse(plugins.contains("userpass")); + } + + @Test + void testGetBuiltinPluginDetails() { + var details = vaultSystemBackendEngine.getPluginDetails("secret", "kv", null); + assertNotNull(details); + assertEquals(true, details.getBuiltin()); + assertEquals("supported", details.getDeprecationStatus()); + assertEquals("kv", details.getName()); + assertNull(details.getType()); + assertTrue(details.getVersion().matches("v[0-9]+\\.[0-9]+\\.[0-9]+\\+builtin")); + assertEquals("", details.getSha256()); + assertEquals("", details.getCommand()); + assertNull(details.getArgs()); + assertNull(details.getEnv()); + } + + @Test + void testGetCustomPluginDetailsWithoutVersionQuery() throws Exception { + var testPluginSHA = registerTestPlugin(false); + + var details = vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", null); + assertNotNull(details); + assertEquals(false, details.getBuiltin()); + assertNull(details.getDeprecationStatus()); + assertEquals("test-plugin", details.getName()); + assertNull(details.getType()); + assertEquals("", details.getVersion()); + assertEquals(testPluginSHA, details.getSha256()); + assertEquals("test-plugin", details.getCommand()); + assertEquals(List.of("--some-flag=1"), details.getArgs()); + // TODO: env vars are not returned by Vault yet + // assertEquals(List.of("ENV_VAR=1"), testPluginDetails.getEnv()); + assertNull(details.getEnv()); + + // Can't get details of an un-versioned custom plugin when specifying a version + assertNull(vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", "v0.0.1")); + } + + @Test + void testGetCustomPluginDetailsWithVersionQuery() throws Exception { + var testPluginSHA = registerTestPlugin(true); + + var details = vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", "v0.0.1"); + assertNotNull(details); + assertEquals(false, details.getBuiltin()); + assertNull(details.getDeprecationStatus()); + assertEquals("test-plugin", details.getName()); + assertNull(details.getType()); + assertEquals("v0.0.1", details.getVersion()); + assertEquals(testPluginSHA, details.getSha256()); + assertEquals("test-plugin", details.getCommand()); + assertEquals(List.of("--some-flag=1"), details.getArgs()); + // TODO: env vars are not returned by Vault yet + // assertEquals(List.of("ENV_VAR=1"), testPluginDetails.getEnv()); + assertNull(details.getEnv()); + + // Can't get details of a versioned custom plugin without specifying a version + assertNull(vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", null)); + } + + @Test + void deregisterPluginWithoutVersion() throws Exception { + registerTestPlugin(false); + + var details = vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", null); + assertNotNull(details); + + vaultSystemBackendEngine.removePlugin("secret", "test-plugin", null); + + details = vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", null); + assertNull(details); + } + + @Test + void deregisterPluginWithVersion() throws Exception { + registerTestPlugin(true); + + var details = vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", "v0.0.1"); + assertNotNull(details); + + vaultSystemBackendEngine.removePlugin("secret", "test-plugin", "v0.0.1"); + + details = vaultSystemBackendEngine.getPluginDetails("secret", "test-plugin", "v0.0.1"); + assertNull(details); + } + + String registerTestPlugin(Boolean includeVersion) throws Exception { + var testPluginSHA = sha256Hex(VaultTestExtension.readResourceData(VaultTestExtension.getTestPluginFilename())); + var version = includeVersion ? "v0.0.1" : null; + vaultSystemBackendEngine.registerPlugin("secret", "test-plugin", version, testPluginSHA, "test-plugin", + List.of("--some-flag=1"), List.of("ENV_VAR=1")); + return testPluginSHA; + } } diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultEnableEngineBody.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultEnableEngineBody.java index 62880395..9f958f37 100644 --- a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultEnableEngineBody.java +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultEnableEngineBody.java @@ -1,5 +1,6 @@ package io.quarkus.vault.runtime.client.dto.sys; +import java.util.List; import java.util.Map; import com.fasterxml.jackson.annotation.JsonProperty; @@ -14,6 +15,30 @@ public static class Config { @JsonProperty("max_lease_ttl") public String maxLeaseTimeToLive; + @JsonProperty("force_no_cache") + public Boolean forceNoCache; + + @JsonProperty("audit_non_hmac_request_keys") + public List auditNonHMACRequestKeys; + + @JsonProperty("audit_non_hmac_response_keys") + public List auditNonHMACResponseKeys; + + @JsonProperty("listing_visibility") + public String listingVisibility; + + @JsonProperty("passthrough_request_headers") + public List passthroughRequestHeaders; + + @JsonProperty("allowed_response_headers") + public List allowedResponseHeaders; + + @JsonProperty("plugin_version") + public String pluginVersion; + + @JsonProperty("allowed_managed_keys") + public List allowedManagedKeys; + } public String type; diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListAllPluginsData.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListAllPluginsData.java new file mode 100644 index 00000000..0362fbb5 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListAllPluginsData.java @@ -0,0 +1,14 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import java.util.List; + +public class VaultListAllPluginsData { + + public List auth; + + public List secret; + + public List database; + public List detailed; + +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListAllPluginsResult.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListAllPluginsResult.java new file mode 100644 index 00000000..28dcf695 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListAllPluginsResult.java @@ -0,0 +1,6 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import io.quarkus.vault.runtime.client.dto.AbstractVaultDTO; + +public class VaultListAllPluginsResult extends AbstractVaultDTO { +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListPluginsData.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListPluginsData.java new file mode 100644 index 00000000..fcbfbe95 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListPluginsData.java @@ -0,0 +1,9 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import java.util.List; + +public class VaultListPluginsData { + + public List keys; + +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListPluginsResult.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListPluginsResult.java new file mode 100644 index 00000000..8b0c49f8 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultListPluginsResult.java @@ -0,0 +1,6 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import io.quarkus.vault.runtime.client.dto.AbstractVaultDTO; + +public class VaultListPluginsResult extends AbstractVaultDTO { +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultPluginDetailsData.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultPluginDetailsData.java new file mode 100644 index 00000000..475ad078 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultPluginDetailsData.java @@ -0,0 +1,35 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import java.util.List; + +import jakarta.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class VaultPluginDetailsData { + + public Boolean builtin; + + @JsonProperty("deprecation_status") + @Nullable + public String deprecationStatus; + + public String name; + + public String type; + + @Nullable + public String version; + + @Nullable + public String sha256; + + @Nullable + public String command; + + @Nullable + public List args; + + @Nullable + public List env; +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultPluginDetailsResult.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultPluginDetailsResult.java new file mode 100644 index 00000000..37735989 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultPluginDetailsResult.java @@ -0,0 +1,6 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import io.quarkus.vault.runtime.client.dto.AbstractVaultDTO; + +public class VaultPluginDetailsResult extends AbstractVaultDTO { +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultRegisterPluginBody.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultRegisterPluginBody.java new file mode 100644 index 00000000..a57ec374 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultRegisterPluginBody.java @@ -0,0 +1,17 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import java.util.List; + +public class VaultRegisterPluginBody { + + public String version; + + public String sha256; + + public String command; + + public List args; + + public List env; + +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultSecretEngineConfigData.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultSecretEngineConfigData.java new file mode 100644 index 00000000..72cb1a30 --- /dev/null +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultSecretEngineConfigData.java @@ -0,0 +1,38 @@ +package io.quarkus.vault.runtime.client.dto.sys; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import io.quarkus.vault.runtime.client.dto.VaultModel; + +public class VaultSecretEngineConfigData implements VaultModel { + + @JsonProperty("default_lease_ttl") + public Long defaultLeaseTimeToLive; + + @JsonProperty("max_lease_ttl") + public Long maxLeaseTimeToLive; + + @JsonProperty("force_no_cache") + public Boolean forceNoCache; + + @JsonProperty("audit_non_hmac_request_keys") + public List auditNonHMACRequestKeys; + + @JsonProperty("audit_non_hmac_response_keys") + public List auditNonHMACResponseKeys; + + @JsonProperty("listing_visibility") + public String listingVisibility; + + @JsonProperty("passthrough_request_headers") + public List passthroughRequestHeaders; + + @JsonProperty("allowed_response_headers") + public List allowedResponseHeaders; + + @JsonProperty("allowed_managed_keys") + public List allowedManagedKeys; + +} diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultSecretEngineInfoData.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultSecretEngineInfoData.java index 2927aae1..ef05c4b3 100644 --- a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultSecretEngineInfoData.java +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultSecretEngineInfoData.java @@ -8,6 +8,8 @@ public class VaultSecretEngineInfoData implements VaultModel { + public VaultSecretEngineConfigData config; + public String description; @JsonProperty("external_entropy_access") @@ -20,5 +22,14 @@ public class VaultSecretEngineInfoData implements VaultModel { public String type; + @JsonProperty("plugin_version") + public String pluginVersion; + + @JsonProperty("running_plugin_version") + public String runningPluginVersion; + + @JsonProperty("running_sha256") + public String runningSha256; + public Map options; } diff --git a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultTuneData.java b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultTuneData.java index ac5adf1f..3614e5a6 100644 --- a/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultTuneData.java +++ b/model/src/main/java/io/quarkus/vault/runtime/client/dto/sys/VaultTuneData.java @@ -1,20 +1,11 @@ package io.quarkus.vault.runtime.client.dto.sys; -import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; -import io.quarkus.vault.runtime.client.dto.VaultModel; - -public class VaultTuneData implements VaultModel { +public class VaultTuneData extends VaultSecretEngineConfigData { public String description; - @JsonProperty("default_lease_ttl") - public Long defaultLeaseTimeToLive; - - @JsonProperty("max_lease_ttl") - public Long maxLeaseTimeToLive; - - @JsonProperty("force_no_cache") - public Boolean forceNoCache; + public Map options; } diff --git a/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendEngine.java b/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendEngine.java index e9d99f14..06d67040 100644 --- a/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendEngine.java +++ b/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendEngine.java @@ -2,6 +2,7 @@ import java.util.List; +import jakarta.annotation.Nullable; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -10,6 +11,8 @@ import io.quarkus.vault.sys.VaultHealth; import io.quarkus.vault.sys.VaultHealthStatus; import io.quarkus.vault.sys.VaultInit; +import io.quarkus.vault.sys.VaultPluginDetails; +import io.quarkus.vault.sys.VaultPlugins; import io.quarkus.vault.sys.VaultSealStatus; import io.quarkus.vault.sys.VaultSecretEngine; import io.quarkus.vault.sys.VaultSecretEngineInfo; @@ -188,4 +191,62 @@ public void disable(String mount) { engine.disable(mount).await().indefinitely(); } + /** + * Lists all available plugins. + * + * @return Map of plugin types to plugin names. + */ + public VaultPlugins listPlugins() { + return engine.listPlugins().await().indefinitely(); + } + + /** + * Lists all available plugins of a specific type. + * + * @param type Plugin type. + * @return List of plugin names. + */ + public List listPlugins(String type) { + return engine.listPlugins(type).await().indefinitely(); + } + + /** + * Gets details for a specific plugin. + * + * @param type Plugin type. + * @param name Plugin name. + * @param version Plugin version. + * @return Plugin info. + */ + public VaultPluginDetails getPluginDetails(String type, String name, @Nullable String version) { + return engine.getPluginDetails(type, name, version).await().indefinitely(); + } + + /** + * Registers a plugin. + * + * @param type Plugin type. + * @param name Plugin name. + * @param version Plugin version. + * @param sha256 SHA256 of the plugin binary. + * @param command Plugin command. + * @param args Plugin args. + * @param env Plugin environment variables. + */ + public void registerPlugin(String type, String name, @Nullable String version, String sha256, String command, + @Nullable List args, @Nullable List env) { + engine.registerPlugin(type, name, version, sha256, command, args, env).await().indefinitely(); + } + + /** + * Deregisters a plugin. + * + * @param type Plugin type. + * @param name Plugin name. + * @param version Plugin version. + */ + public void removePlugin(String type, String name, @Nullable String version) { + engine.removePlugin(type, name, version).await().indefinitely(); + } + } diff --git a/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendReactiveEngine.java b/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendReactiveEngine.java index d5cb70b1..956f3fc6 100644 --- a/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendReactiveEngine.java +++ b/runtime/src/main/java/io/quarkus/vault/VaultSystemBackendReactiveEngine.java @@ -1,12 +1,17 @@ package io.quarkus.vault; import java.util.List; +import java.util.Map; + +import jakarta.annotation.Nullable; import io.quarkus.vault.runtime.config.VaultRuntimeConfig; import io.quarkus.vault.sys.EnableEngineOptions; import io.quarkus.vault.sys.VaultHealth; import io.quarkus.vault.sys.VaultHealthStatus; import io.quarkus.vault.sys.VaultInit; +import io.quarkus.vault.sys.VaultPluginDetails; +import io.quarkus.vault.sys.VaultPlugins; import io.quarkus.vault.sys.VaultSealStatus; import io.quarkus.vault.sys.VaultSecretEngine; import io.quarkus.vault.sys.VaultSecretEngineInfo; @@ -147,4 +152,53 @@ public interface VaultSystemBackendReactiveEngine { */ Uni disable(String mount); + /** + * Lists all available plugins. + * + * @return Map of plugin types to plugin names. + */ + Uni listPlugins(); + + /** + * Lists all available plugins of a specific type. + * + * @param type Plugin type. + * @return List of plugin names. + */ + Uni> listPlugins(String type); + + /** + * Gets details for a specific plugin. + * + * @param type Plugin type. + * @param name Plugin name. + * @param version Plugin version. + * @return Plugin info. + */ + Uni getPluginDetails(String type, String name, @Nullable String version); + + /** + * Registers a plugin. + * + * @param type Plugin type. + * @param name Plugin name. + * @param version Plugin version. + * @param sha256 SHA256 of the plugin binary. + * @param command Plugin command. + * @param args Plugin args. + * @param env Plugin environment variables. + * @return Plugin registration status. + */ + Uni registerPlugin(String type, String name, @Nullable String version, String sha256, String command, + @Nullable List args, @Nullable List env); + + /** + * Deregisters a plugin. + * + * @param type Plugin type. + * @param name Plugin name. + * @param version Plugin version. + */ + Uni removePlugin(String type, String name, @Nullable String version); + } diff --git a/runtime/src/main/java/io/quarkus/vault/runtime/VaultSystemBackendManager.java b/runtime/src/main/java/io/quarkus/vault/runtime/VaultSystemBackendManager.java index 783a1bcf..9adbefaa 100644 --- a/runtime/src/main/java/io/quarkus/vault/runtime/VaultSystemBackendManager.java +++ b/runtime/src/main/java/io/quarkus/vault/runtime/VaultSystemBackendManager.java @@ -1,7 +1,9 @@ package io.quarkus.vault.runtime; import java.util.List; +import java.util.stream.Collectors; +import jakarta.annotation.Nullable; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -11,12 +13,16 @@ import io.quarkus.vault.runtime.client.backend.VaultInternalSystemBackend; import io.quarkus.vault.runtime.client.dto.sys.VaultEnableEngineBody; import io.quarkus.vault.runtime.client.dto.sys.VaultPolicyBody; +import io.quarkus.vault.runtime.client.dto.sys.VaultRegisterPluginBody; import io.quarkus.vault.runtime.client.dto.sys.VaultTuneBody; import io.quarkus.vault.runtime.config.VaultBuildTimeConfig; import io.quarkus.vault.sys.EnableEngineOptions; +import io.quarkus.vault.sys.EngineListingVisibility; import io.quarkus.vault.sys.VaultHealth; import io.quarkus.vault.sys.VaultHealthStatus; import io.quarkus.vault.sys.VaultInit; +import io.quarkus.vault.sys.VaultPluginDetails; +import io.quarkus.vault.sys.VaultPlugins; import io.quarkus.vault.sys.VaultSealStatus; import io.quarkus.vault.sys.VaultSecretEngine; import io.quarkus.vault.sys.VaultSecretEngineInfo; @@ -143,7 +149,22 @@ public Uni getSecretEngineInfo(String mount) { info.setLocal(result.data.local); info.setExternalEntropyAccess(result.data.externalEntropyAccess); info.setSealWrap(result.data.sealWrap); + info.setPluginVersion(result.data.pluginVersion); + info.setRunningPluginVersion(result.data.runningPluginVersion); + info.setRunningSha256(result.data.runningSha256); + info.setDefaultLeaseTimeToLive(result.data.config.defaultLeaseTimeToLive); + info.setMaxLeaseTimeToLive(result.data.config.maxLeaseTimeToLive); + info.setForceNoCache(result.data.config.forceNoCache); info.setOptions(result.data.options); + info.setAuditNonHMACRequestKeys(result.data.config.auditNonHMACRequestKeys); + info.setAuditNonHMACResponseKeys(result.data.config.auditNonHMACResponseKeys); + info.setListingVisibility(result.data.config.listingVisibility != null + ? EngineListingVisibility.valueOf(result.data.config.listingVisibility + .toUpperCase()) + : null); + info.setPassthroughRequestHeaders(result.data.config.passthroughRequestHeaders); + info.setAllowedResponseHeaders(result.data.config.allowedResponseHeaders); + info.setAllowedManagedKeys(result.data.config.allowedManagedKeys); return info; }); }); @@ -158,6 +179,16 @@ public Uni getTuneInfo(String mount) { tuneInfo.setMaxLeaseTimeToLive(vaultTuneResult.data.maxLeaseTimeToLive); tuneInfo.setDescription(vaultTuneResult.data.description); tuneInfo.setForceNoCache(vaultTuneResult.data.forceNoCache); + tuneInfo.setOptions(vaultTuneResult.data.options); + tuneInfo.setAuditNonHMACRequestKeys(vaultTuneResult.data.auditNonHMACRequestKeys); + tuneInfo.setAuditNonHMACResponseKeys(vaultTuneResult.data.auditNonHMACResponseKeys); + tuneInfo.setListingVisibility(vaultTuneResult.data.listingVisibility != null + ? EngineListingVisibility.valueOf(vaultTuneResult.data.listingVisibility + .toUpperCase()) + : null); + tuneInfo.setPassthroughRequestHeaders(vaultTuneResult.data.passthroughRequestHeaders); + tuneInfo.setAllowedResponseHeaders(vaultTuneResult.data.allowedResponseHeaders); + tuneInfo.setAllowedManagedKeys(vaultTuneResult.data.allowedManagedKeys); return tuneInfo; }); }); @@ -205,6 +236,15 @@ public Uni enable(String engineType, String mount, String description, Ena body.config = new VaultEnableEngineBody.Config(); body.config.defaultLeaseTimeToLive = options.defaultLeaseTimeToLive; body.config.maxLeaseTimeToLive = options.maxLeaseTimeToLive; + body.config.forceNoCache = options.forceNoCache; + body.config.auditNonHMACRequestKeys = options.auditNonHMACRequestKeys; + body.config.auditNonHMACResponseKeys = options.auditNonHMACResponseKeys; + body.config.listingVisibility = options.listingVisibility != null ? options.listingVisibility.name().toLowerCase() + : null; + body.config.passthroughRequestHeaders = options.passthroughRequestHeaders; + body.config.allowedResponseHeaders = options.allowedResponseHeaders; + body.config.pluginVersion = options.pluginVersion; + body.config.allowedManagedKeys = options.allowedManagedKeys; body.options = options.options; return vaultAuthManager.getClientToken(vaultClient).flatMap(token -> { @@ -218,4 +258,78 @@ public Uni disable(String mount) { return vaultInternalSystemBackend.disableEngine(vaultClient, token, mount); }); } + + @Override + public Uni listPlugins() { + return vaultAuthManager.getClientToken(vaultClient).flatMap(token -> { + return vaultInternalSystemBackend.listPlugins(vaultClient, token).map(r -> new VaultPlugins() + .setAuth(r.data.auth) + .setDatabase(r.data.database) + .setSecret(r.data.secret) + .setDetailed(r.data.detailed.stream().map(d -> new VaultPluginDetails() + .setBuiltin(d.builtin) + .setDeprecationStatus(d.deprecationStatus) + .setName(d.name) + .setType(d.type) + .setVersion(d.version) + .setSha256(d.sha256) + .setCommand(d.command) + .setArgs(d.args) + .setEnv(d.env)).collect(Collectors.toList()))); + }); + } + + @Override + public Uni> listPlugins(String type) { + return vaultAuthManager.getClientToken(vaultClient).flatMap(token -> { + return vaultInternalSystemBackend.listPlugins(vaultClient, token, type).map(r -> r.data.keys); + }); + } + + @Override + public Uni getPluginDetails(String type, String name, @Nullable String version) { + return vaultAuthManager.getClientToken(vaultClient).flatMap(token -> { + return vaultInternalSystemBackend.getPluginDetails(vaultClient, token, type, name, version) + .map(r -> new VaultPluginDetails() + .setBuiltin(r.data.builtin) + .setDeprecationStatus(r.data.deprecationStatus) + .setName(r.data.name) + .setType(r.data.type) + .setVersion(r.data.version) + .setSha256(r.data.sha256) + .setCommand(r.data.command) + .setArgs(r.data.args) + .setEnv(r.data.env)); + }) + .onFailure(VaultClientException.class).recoverWithUni(x -> { + VaultClientException vx = (VaultClientException) x; + if (vx.getStatus() == 404) { + return Uni.createFrom().nullItem(); + } else { + return Uni.createFrom().failure(x); + } + }); + } + + @Override + public Uni registerPlugin(String type, String name, @Nullable String version, String sha256, String command, + @Nullable List args, @Nullable List env) { + var body = new VaultRegisterPluginBody(); + body.version = version; + body.sha256 = sha256; + body.command = command; + body.args = args; + body.env = env; + + return vaultAuthManager.getClientToken(vaultClient).flatMap(token -> { + return vaultInternalSystemBackend.registerPlugin(vaultClient, token, type, name, body); + }); + } + + @Override + public Uni removePlugin(String type, String name, @Nullable String version) { + return vaultAuthManager.getClientToken(vaultClient).flatMap(token -> { + return vaultInternalSystemBackend.removePlugin(vaultClient, token, type, name, version); + }); + } } diff --git a/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java b/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java index 148e7c17..2b8883b9 100644 --- a/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java +++ b/runtime/src/main/java/io/quarkus/vault/runtime/VaultVersions.java @@ -2,6 +2,6 @@ public class VaultVersions { - public static final String VAULT_TEST_VERSION = "1.15.0"; + public static final String VAULT_TEST_VERSION = "1.15.2"; } diff --git a/runtime/src/main/java/io/quarkus/vault/runtime/client/backend/VaultInternalSystemBackend.java b/runtime/src/main/java/io/quarkus/vault/runtime/client/backend/VaultInternalSystemBackend.java index 7ef65964..0866a5bd 100644 --- a/runtime/src/main/java/io/quarkus/vault/runtime/client/backend/VaultInternalSystemBackend.java +++ b/runtime/src/main/java/io/quarkus/vault/runtime/client/backend/VaultInternalSystemBackend.java @@ -15,9 +15,13 @@ import io.quarkus.vault.runtime.client.dto.sys.VaultInitResponse; import io.quarkus.vault.runtime.client.dto.sys.VaultLeasesBody; import io.quarkus.vault.runtime.client.dto.sys.VaultLeasesLookup; +import io.quarkus.vault.runtime.client.dto.sys.VaultListAllPluginsResult; +import io.quarkus.vault.runtime.client.dto.sys.VaultListPluginsResult; import io.quarkus.vault.runtime.client.dto.sys.VaultListPolicyResult; +import io.quarkus.vault.runtime.client.dto.sys.VaultPluginDetailsResult; import io.quarkus.vault.runtime.client.dto.sys.VaultPolicyBody; import io.quarkus.vault.runtime.client.dto.sys.VaultPolicyResult; +import io.quarkus.vault.runtime.client.dto.sys.VaultRegisterPluginBody; import io.quarkus.vault.runtime.client.dto.sys.VaultRenewLease; import io.quarkus.vault.runtime.client.dto.sys.VaultSealStatusResult; import io.quarkus.vault.runtime.client.dto.sys.VaultSecretEngineInfoResult; @@ -124,4 +128,30 @@ private Map getHealthParams(boolean isStandByOk, boolean isPerfS return queryParams; } + + public Uni listPlugins(VaultClient vaultClient, String token) { + return vaultClient.get(opName("List Plugins"), "sys/plugins/catalog", token, VaultListAllPluginsResult.class); + } + + public Uni listPlugins(VaultClient vaultClient, String token, String type) { + return vaultClient.list(opName("List Plugins (" + type + ")"), "sys/plugins/catalog/" + type, token, + VaultListPluginsResult.class); + } + + public Uni getPluginDetails(VaultClient vaultClient, String token, String type, String name, + String version) { + var query = version != null ? "?version=" + version : ""; + return vaultClient.get(opName("Get Plugin Details"), "sys/plugins/catalog/" + type + "/" + name + query, token, + VaultPluginDetailsResult.class); + } + + public Uni registerPlugin(VaultClient vaultClient, String token, String type, String name, + VaultRegisterPluginBody body) { + return vaultClient.post(opName("Register Plugin"), "sys/plugins/catalog/" + type + "/" + name, token, body, 204); + } + + public Uni removePlugin(VaultClient vaultClient, String token, String type, String name, String version) { + var query = version != null ? "?version=" + version : ""; + return vaultClient.delete(opName("Remove Plugin"), "sys/plugins/catalog/" + type + "/" + name + query, token, 204); + } } diff --git a/runtime/src/main/java/io/quarkus/vault/runtime/client/secretengine/VaultInternalKvV2SecretEngine.java b/runtime/src/main/java/io/quarkus/vault/runtime/client/secretengine/VaultInternalKvV2SecretEngine.java index 02eb4d39..2fbe2947 100644 --- a/runtime/src/main/java/io/quarkus/vault/runtime/client/secretengine/VaultInternalKvV2SecretEngine.java +++ b/runtime/src/main/java/io/quarkus/vault/runtime/client/secretengine/VaultInternalKvV2SecretEngine.java @@ -4,7 +4,10 @@ import io.quarkus.vault.runtime.client.VaultClient; import io.quarkus.vault.runtime.client.VaultInternalBase; -import io.quarkus.vault.runtime.client.dto.kv.*; +import io.quarkus.vault.runtime.client.dto.kv.VaultKvListSecrets; +import io.quarkus.vault.runtime.client.dto.kv.VaultKvSecretJsonV2; +import io.quarkus.vault.runtime.client.dto.kv.VaultKvSecretV2Write; +import io.quarkus.vault.runtime.client.dto.kv.VaultKvSecretV2WriteBody; import io.smallrye.mutiny.Uni; @Singleton diff --git a/runtime/src/main/java/io/quarkus/vault/sys/EnableEngineOptions.java b/runtime/src/main/java/io/quarkus/vault/sys/EnableEngineOptions.java index 0b99505d..5b12f5c9 100644 --- a/runtime/src/main/java/io/quarkus/vault/sys/EnableEngineOptions.java +++ b/runtime/src/main/java/io/quarkus/vault/sys/EnableEngineOptions.java @@ -1,5 +1,6 @@ package io.quarkus.vault.sys; +import java.util.List; import java.util.Map; /** @@ -17,6 +18,49 @@ public class EnableEngineOptions { */ public String maxLeaseTimeToLive; + /** + * Disable caching + */ + public Boolean forceNoCache; + + /** + * List of keys that will not be HMAC'd by audit devices in the request data object. + */ + public List auditNonHMACRequestKeys; + + /** + * List of keys that will not be HMAC'd by audit devices in the response data object. + */ + public List auditNonHMACResponseKeys; + + /** + * Specifies whether to show this mount in the UI-specific listing endpoint. Valid values are "unauth" + * or "hidden". If not set, behaves like "hidden". + */ + public EngineListingVisibility listingVisibility; + + /** + * List of headers to allow and pass from the request to the plugin. + */ + public List passthroughRequestHeaders; + + /** + * List of headers to allow, allowing a plugin to include them in the response. + */ + public List allowedResponseHeaders; + + /** + * Specifies the semantic version of the plugin to use, e.g. "v1.0.0". If unspecified, the server + * will select any matching unversioned plugin that may have been registered, the latest versioned + * plugin registered, or a built-in plugin in that order of precendence. + */ + public String pluginVersion; + + /** + * List of managed key registry entry names that the mount in question is allowed to access. + */ + public List allowedManagedKeys; + /** * Engine specific mount options */ @@ -32,6 +76,46 @@ public EnableEngineOptions setMaxLeaseTimeToLive(String maxLeaseTimeToLive) { return this; } + public EnableEngineOptions setForceNoCache(Boolean forceNoCache) { + this.forceNoCache = forceNoCache; + return this; + } + + public EnableEngineOptions setAuditNonHMACRequestKeys(List auditNonHMACRequestKeys) { + this.auditNonHMACRequestKeys = auditNonHMACRequestKeys; + return this; + } + + public EnableEngineOptions setAuditNonHMACResponseKeys(List auditNonHMACResponseKeys) { + this.auditNonHMACResponseKeys = auditNonHMACResponseKeys; + return this; + } + + public EnableEngineOptions setListingVisibility(EngineListingVisibility listingVisibility) { + this.listingVisibility = listingVisibility; + return this; + } + + public EnableEngineOptions setPassthroughRequestHeaders(List passthroughRequestHeaders) { + this.passthroughRequestHeaders = passthroughRequestHeaders; + return this; + } + + public EnableEngineOptions setAllowedResponseHeaders(List allowedResponseHeaders) { + this.allowedResponseHeaders = allowedResponseHeaders; + return this; + } + + public EnableEngineOptions setPluginVersion(String pluginVersion) { + this.pluginVersion = pluginVersion; + return this; + } + + public EnableEngineOptions setAllowedManagedKeys(List allowedManagedKeys) { + this.allowedManagedKeys = allowedManagedKeys; + return this; + } + public EnableEngineOptions setOptions(Map options) { this.options = options; return this; diff --git a/runtime/src/main/java/io/quarkus/vault/sys/EngineListingVisibility.java b/runtime/src/main/java/io/quarkus/vault/sys/EngineListingVisibility.java new file mode 100644 index 00000000..e928ba7d --- /dev/null +++ b/runtime/src/main/java/io/quarkus/vault/sys/EngineListingVisibility.java @@ -0,0 +1,6 @@ +package io.quarkus.vault.sys; + +public enum EngineListingVisibility { + UNAUTH, + HIDDEN +} diff --git a/runtime/src/main/java/io/quarkus/vault/sys/VaultPluginDetails.java b/runtime/src/main/java/io/quarkus/vault/sys/VaultPluginDetails.java new file mode 100644 index 00000000..c0d5267a --- /dev/null +++ b/runtime/src/main/java/io/quarkus/vault/sys/VaultPluginDetails.java @@ -0,0 +1,105 @@ +package io.quarkus.vault.sys; + +import java.util.List; + +public class VaultPluginDetails { + + private Boolean builtin; + + private String deprecationStatus; + + private String name; + + private String type; + + private String version; + + private String sha256; + + private String command; + + private List args; + + private List env; + + public Boolean getBuiltin() { + return builtin; + } + + public VaultPluginDetails setBuiltin(Boolean builtin) { + this.builtin = builtin; + return this; + } + + public String getDeprecationStatus() { + return deprecationStatus; + } + + public VaultPluginDetails setDeprecationStatus(String deprecationStatus) { + this.deprecationStatus = deprecationStatus; + return this; + } + + public String getName() { + return name; + } + + public VaultPluginDetails setName(String name) { + this.name = name; + return this; + } + + public String getType() { + return type; + } + + public VaultPluginDetails setType(String type) { + this.type = type; + return this; + } + + public String getVersion() { + return version; + } + + public VaultPluginDetails setVersion(String version) { + this.version = version; + return this; + } + + public String getSha256() { + return sha256; + } + + public VaultPluginDetails setSha256(String sha256) { + this.sha256 = sha256; + return this; + } + + public String getCommand() { + return command; + } + + public VaultPluginDetails setCommand(String command) { + this.command = command; + return this; + } + + public List getArgs() { + return args; + } + + public VaultPluginDetails setArgs(List args) { + this.args = args; + return this; + } + + public List getEnv() { + return env; + } + + public VaultPluginDetails setEnv(List env) { + this.env = env; + return this; + } +} diff --git a/runtime/src/main/java/io/quarkus/vault/sys/VaultPlugins.java b/runtime/src/main/java/io/quarkus/vault/sys/VaultPlugins.java new file mode 100644 index 00000000..1bbb7b0c --- /dev/null +++ b/runtime/src/main/java/io/quarkus/vault/sys/VaultPlugins.java @@ -0,0 +1,47 @@ +package io.quarkus.vault.sys; + +import java.util.List; + +public class VaultPlugins { + + private List auth; + private List database; + private List secret; + private List detailed; + + public List getAuth() { + return auth; + } + + public VaultPlugins setAuth(List auth) { + this.auth = auth; + return this; + } + + public List getDatabase() { + return database; + } + + public VaultPlugins setDatabase(List database) { + this.database = database; + return this; + } + + public List getSecret() { + return secret; + } + + public VaultPlugins setSecret(List secret) { + this.secret = secret; + return this; + } + + public List getDetailed() { + return detailed; + } + + public VaultPlugins setDetailed(List detailed) { + this.detailed = detailed; + return this; + } +} diff --git a/runtime/src/main/java/io/quarkus/vault/sys/VaultSecretEngineInfo.java b/runtime/src/main/java/io/quarkus/vault/sys/VaultSecretEngineInfo.java index 979778ea..5bee5f7c 100644 --- a/runtime/src/main/java/io/quarkus/vault/sys/VaultSecretEngineInfo.java +++ b/runtime/src/main/java/io/quarkus/vault/sys/VaultSecretEngineInfo.java @@ -1,5 +1,6 @@ package io.quarkus.vault.sys; +import java.util.List; import java.util.Map; public class VaultSecretEngineInfo { @@ -14,8 +15,32 @@ public class VaultSecretEngineInfo { private String type; + private String pluginVersion; + + private String runningPluginVersion; + + private String runningSha256; + + public Long defaultLeaseTimeToLive; + + public Long maxLeaseTimeToLive; + + public Boolean forceNoCache; + private Map options; + private List auditNonHMACRequestKeys; + + private List auditNonHMACResponseKeys; + + private EngineListingVisibility listingVisibility; + + private List passthroughRequestHeaders; + + private List allowedResponseHeaders; + + private List allowedManagedKeys; + public Boolean getExternalEntropyAccess() { return externalEntropyAccess; } @@ -32,12 +57,60 @@ public String getDescription() { return description; } + public String getType() { + return type; + } + + public String getPluginVersion() { + return pluginVersion; + } + + public String getRunningPluginVersion() { + return runningPluginVersion; + } + + public String getRunningSha256() { + return runningSha256; + } + + public Long getDefaultLeaseTimeToLive() { + return defaultLeaseTimeToLive; + } + + public Long getMaxLeaseTimeToLive() { + return maxLeaseTimeToLive; + } + + public Boolean getForceNoCache() { + return forceNoCache; + } + public Map getOptions() { return options; } - public String getType() { - return type; + public List getAuditNonHMACRequestKeys() { + return auditNonHMACRequestKeys; + } + + public List getAuditNonHMACResponseKeys() { + return auditNonHMACResponseKeys; + } + + public EngineListingVisibility getListingVisibility() { + return listingVisibility; + } + + public List getPassthroughRequestHeaders() { + return passthroughRequestHeaders; + } + + public List getAllowedResponseHeaders() { + return allowedResponseHeaders; + } + + public List getAllowedManagedKeys() { + return allowedManagedKeys; } public VaultSecretEngineInfo setDescription(String description) { @@ -65,8 +138,68 @@ public VaultSecretEngineInfo setType(String type) { return this; } + public VaultSecretEngineInfo setPluginVersion(String pluginVersion) { + this.pluginVersion = pluginVersion; + return this; + } + + public VaultSecretEngineInfo setRunningPluginVersion(String runningPluginVersion) { + this.runningPluginVersion = runningPluginVersion; + return this; + } + + public VaultSecretEngineInfo setRunningSha256(String runningSha256) { + this.runningSha256 = runningSha256; + return this; + } + + public VaultSecretEngineInfo setDefaultLeaseTimeToLive(Long defaultLeaseTimeToLive) { + this.defaultLeaseTimeToLive = defaultLeaseTimeToLive; + return this; + } + + public VaultSecretEngineInfo setMaxLeaseTimeToLive(Long maxLeaseTimeToLive) { + this.maxLeaseTimeToLive = maxLeaseTimeToLive; + return this; + } + + public VaultSecretEngineInfo setForceNoCache(Boolean forceNoCache) { + this.forceNoCache = forceNoCache; + return this; + } + public VaultSecretEngineInfo setOptions(Map options) { this.options = options; return this; } + + public VaultSecretEngineInfo setAuditNonHMACRequestKeys(List auditNonHMACRequestKeys) { + this.auditNonHMACRequestKeys = auditNonHMACRequestKeys; + return this; + } + + public VaultSecretEngineInfo setAuditNonHMACResponseKeys(List auditNonHMACResponseKeys) { + this.auditNonHMACResponseKeys = auditNonHMACResponseKeys; + return this; + } + + public VaultSecretEngineInfo setListingVisibility(EngineListingVisibility listingVisibility) { + this.listingVisibility = listingVisibility; + return this; + } + + public VaultSecretEngineInfo setPassthroughRequestHeaders(List passthroughRequestHeaders) { + this.passthroughRequestHeaders = passthroughRequestHeaders; + return this; + } + + public VaultSecretEngineInfo setAllowedResponseHeaders(List allowedResponseHeaders) { + this.allowedResponseHeaders = allowedResponseHeaders; + return this; + } + + public VaultSecretEngineInfo setAllowedManagedKeys(List allowedManagedKeys) { + this.allowedManagedKeys = allowedManagedKeys; + return this; + } } diff --git a/runtime/src/main/java/io/quarkus/vault/sys/VaultTuneInfo.java b/runtime/src/main/java/io/quarkus/vault/sys/VaultTuneInfo.java index 3627d1e4..9641862a 100644 --- a/runtime/src/main/java/io/quarkus/vault/sys/VaultTuneInfo.java +++ b/runtime/src/main/java/io/quarkus/vault/sys/VaultTuneInfo.java @@ -1,11 +1,21 @@ package io.quarkus.vault.sys; +import java.util.List; +import java.util.Map; + public class VaultTuneInfo { private String description; private Long defaultLeaseTimeToLive; private Long maxLeaseTimeToLive; private Boolean forceNoCache; + private Map options; + private List auditNonHMACRequestKeys; + private List auditNonHMACResponseKeys; + private EngineListingVisibility listingVisibility; + private List passthroughRequestHeaders; + private List allowedResponseHeaders; + private List allowedManagedKeys; public String getDescription() { return description; @@ -29,6 +39,34 @@ public Long getMaxLeaseTimeToLive() { return maxLeaseTimeToLive; } + public Map getOptions() { + return options; + } + + public List getAuditNonHMACRequestKeys() { + return auditNonHMACRequestKeys; + } + + public List getAuditNonHMACResponseKeys() { + return auditNonHMACResponseKeys; + } + + public EngineListingVisibility getListingVisibility() { + return listingVisibility; + } + + public List getPassthroughRequestHeaders() { + return passthroughRequestHeaders; + } + + public List getAllowedResponseHeaders() { + return allowedResponseHeaders; + } + + public List getAllowedManagedKeys() { + return allowedManagedKeys; + } + public VaultTuneInfo setMaxLeaseTimeToLive(Long maxLeaseTimeToLive) { this.maxLeaseTimeToLive = maxLeaseTimeToLive; return this; @@ -42,4 +80,39 @@ public VaultTuneInfo setForceNoCache(Boolean forceNoCache) { this.forceNoCache = forceNoCache; return this; } + + public VaultTuneInfo setOptions(Map options) { + this.options = options; + return this; + } + + public VaultTuneInfo setAuditNonHMACRequestKeys(List auditNonHMACRequestKeys) { + this.auditNonHMACRequestKeys = auditNonHMACRequestKeys; + return this; + } + + public VaultTuneInfo setAuditNonHMACResponseKeys(List auditNonHMACResponseKeys) { + this.auditNonHMACResponseKeys = auditNonHMACResponseKeys; + return this; + } + + public VaultTuneInfo setListingVisibility(EngineListingVisibility listingVisibility) { + this.listingVisibility = listingVisibility; + return this; + } + + public VaultTuneInfo setPassthroughRequestHeaders(List passthroughRequestHeaders) { + this.passthroughRequestHeaders = passthroughRequestHeaders; + return this; + } + + public VaultTuneInfo setAllowedResponseHeaders(List allowedResponseHeaders) { + this.allowedResponseHeaders = allowedResponseHeaders; + return this; + } + + public VaultTuneInfo setAllowedManagedKeys(List allowedManagedKeys) { + this.allowedManagedKeys = allowedManagedKeys; + return this; + } } diff --git a/test-framework/src/main/java/io/quarkus/vault/test/VaultTestExtension.java b/test-framework/src/main/java/io/quarkus/vault/test/VaultTestExtension.java index f556e0e8..11510e35 100644 --- a/test-framework/src/main/java/io/quarkus/vault/test/VaultTestExtension.java +++ b/test-framework/src/main/java/io/quarkus/vault/test/VaultTestExtension.java @@ -14,10 +14,8 @@ import static org.testcontainers.containers.BindMode.READ_ONLY; import static org.testcontainers.containers.PostgreSQLContainer.POSTGRESQL_PORT; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Files; @@ -267,6 +265,7 @@ public void start() throws InterruptedException, IOException { .withClasspathResourceMapping("vault-postgres-creation.sql", TMP_VAULT_POSTGRES_CREATION_SQL_FILE, READ_ONLY) .withClasspathResourceMapping("secret.json", "/tmp/secret.json", READ_ONLY) .withClasspathResourceMapping("config.json", "/tmp/config.json", READ_ONLY) + .withClasspathResourceMapping(getTestPluginFilename(), "/vault/plugins/test-plugin", READ_ONLY) .withCommand("server", "-log-level=debug", "-config=" + TMP_VAULT_CONFIG_JSON_FILE); vaultContainer.setPortBindings(Arrays.asList(VAULT_PORT + ":" + VAULT_PORT)); @@ -337,6 +336,9 @@ private void initVault() throws InterruptedException, IOException { .await() .indefinitely(); + // executable permission for test-plugin + execVault("chmod +x /vault/plugins/test-plugin"); + // static secrets kv v1 execVault(format("vault secrets enable -path=%s kv", SECRET_PATH_V1)); execVault(format("vault kv put %s/%s %s=%s", SECRET_PATH_V1, APP_SECRET_PATH, SECRET_KEY, SECRET_VALUE)); @@ -453,19 +455,12 @@ private void initVault() throws InterruptedException, IOException { execVault("vault token create -policy=root -id=pkiroot"); } - private String readResourceContent(String path) throws IOException { - int count; - byte[] buf = new byte[512]; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path); - try { - while ((count = in.read(buf)) > 0) { - baos.write(buf, 0, count); - } - } finally { - in.close(); - } - return new String(baos.toByteArray()); + public static String readResourceContent(String path) throws IOException { + return new String(readResourceData(path)); + } + + public static byte[] readResourceData(String path) throws IOException { + return Thread.currentThread().getContextClassLoader().getResourceAsStream(path).readAllBytes(); } private String fetchWrappingToken(String out) { @@ -478,6 +473,15 @@ private String fetchWrappingToken(String out) { } } + public static String getTestPluginFilename() { + return "vault-test-plugin-linux-" + getPluginArchitecture(); + } + + public static String getPluginArchitecture() { + var osArch = System.getProperty("os.arch"); + return osArch.contains("aarch") || osArch.contains("arm") ? "arm64" : "amd64"; + } + public static boolean useTls() { return System.getProperty("vault-test-extension.use-tls", TRUE.toString()).equals(TRUE.toString()); } diff --git a/test-framework/src/main/resources/vault-config-tls.json b/test-framework/src/main/resources/vault-config-tls.json index 8a98b7ae..0bf072ae 100644 --- a/test-framework/src/main/resources/vault-config-tls.json +++ b/test-framework/src/main/resources/vault-config-tls.json @@ -12,5 +12,6 @@ "tls_key_file": "/tmp/vault-tls.key", "tls_disable": "false" } - } + }, + "plugin_directory": "/vault/plugins" } \ No newline at end of file diff --git a/test-framework/src/main/resources/vault-config.json b/test-framework/src/main/resources/vault-config.json index 79123ab2..c8157a8d 100644 --- a/test-framework/src/main/resources/vault-config.json +++ b/test-framework/src/main/resources/vault-config.json @@ -10,5 +10,6 @@ { "address": "0.0.0.0:8200", "tls_disable": "true" } - } + }, + "plugin_directory": "/vault/plugins" } \ No newline at end of file diff --git a/test-framework/src/main/resources/vault-test-plugin-linux-amd64 b/test-framework/src/main/resources/vault-test-plugin-linux-amd64 new file mode 100755 index 00000000..23a00078 Binary files /dev/null and b/test-framework/src/main/resources/vault-test-plugin-linux-amd64 differ diff --git a/test-framework/src/main/resources/vault-test-plugin-linux-arm64 b/test-framework/src/main/resources/vault-test-plugin-linux-arm64 new file mode 100755 index 00000000..ab9106a9 Binary files /dev/null and b/test-framework/src/main/resources/vault-test-plugin-linux-arm64 differ diff --git a/test-framework/src/main/resources/vault.policy b/test-framework/src/main/resources/vault.policy index f383d6b7..ce4339ad 100644 --- a/test-framework/src/main/resources/vault.policy +++ b/test-framework/src/main/resources/vault.policy @@ -79,7 +79,7 @@ path "totp/*" { } path "sys/*" { - capabilities = ["read", "create", "update", "delete", "list"] + capabilities = ["read", "create", "update", "delete", "list", "sudo"] } path "auth/kubernetes/*" {