diff --git a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/HashiCorpVaultCommunicationService.java b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/HashiCorpVaultCommunicationService.java index 8e9f8c5594..840db72ffa 100644 --- a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/HashiCorpVaultCommunicationService.java +++ b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/HashiCorpVaultCommunicationService.java @@ -46,39 +46,39 @@ public interface HashiCorpVaultCommunicationService { byte[] decrypt(String transitPath, String cipherText); /** - * Writes a single secret value using Vault's unversioned Key/Value Secrets Engine. + * Writes a single secret value using Vault's Key/Value Secrets Engine. * - * @see https://www.vaultproject.io/api-docs/secret/kv/kv-v1 - * @param keyValuePath The Vault path to use for the configured Key/Value v1 Secrets Engine + * @see https://www.vaultproject.io/api-docs/secret/kv + * @param keyValuePath The Vault path to use for the configured Key/Value Secrets Engine * @param secretKey The secret key * @param value The secret value */ void writeKeyValueSecret(String keyValuePath, String secretKey, String value); /** - * Reads a single secret value from Vault's unversioned Key/Value Secrets Engine. + * Reads a single secret value from Vault's Key/Value Secrets Engine. * - * @see https://www.vaultproject.io/api-docs/secret/kv/kv-v1 - * @param keyValuePath The Vault path to use for the configured Key/Value v1 Secrets Engine + * @see https://www.vaultproject.io/api-docs/secret/kv + * @param keyValuePath The Vault path to use for the configured Key/Value Secrets Engine * @param secretKey The secret key * @return The secret value, or empty if not found */ Optional readKeyValueSecret(String keyValuePath, String secretKey); /** - * Writes a secret with multiple key/value pairs using Vault's unversioned Key/Value Secrets Engine. + * Writes a secret with multiple key/value pairs using Vault's Key/Value Secrets Engine. * - * @see https://www.vaultproject.io/api-docs/secret/kv/kv-v1 - * @param keyValuePath The Vault path to use for the configured Key/Value v1 Secrets Engine + * @see https://www.vaultproject.io/api-docs/secret/kv + * @param keyValuePath The Vault path to use for the configured Key/Value Secrets Engine * @param keyValues A map from key to value for keys/values that should be stored in the secret */ void writeKeyValueSecretMap(String keyValuePath, String secretKey, Map keyValues); /** - * Reads a secret with multiple key/value pairs from Vault's unversioned Key/Value Secrets Engine. + * Reads a secret with multiple key/value pairs from Vault's Key/Value Secrets Engine. * - * @see https://www.vaultproject.io/api-docs/secret/kv/kv-v1 - * @param keyValuePath The Vault path to use for the configured Key/Value v1 Secrets Engine + * @see https://www.vaultproject.io/api-docs/secret/kv + * @param keyValuePath The Vault path to use for the configured Key/Value Secrets Engine * @param secretKey The secret key * @return A map from key to value from the secret key/values, or an empty map if not found */ diff --git a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationService.java b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationService.java index 34508436d3..a407b85eed 100644 --- a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationService.java +++ b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationService.java @@ -25,6 +25,7 @@ import org.springframework.core.env.PropertySource; import org.springframework.vault.authentication.SimpleSessionManager; import org.springframework.vault.client.ClientHttpRequestFactoryFactory; import org.springframework.vault.core.VaultKeyValueOperations; +import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend; import org.springframework.vault.core.VaultTemplate; import org.springframework.vault.core.VaultTransitOperations; import org.springframework.vault.support.Ciphertext; @@ -37,8 +38,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import static org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend.KV_1; - /** * Implements the VaultCommunicationService using Spring Vault */ @@ -46,6 +45,7 @@ public class StandardHashiCorpVaultCommunicationService implements HashiCorpVaul private final VaultTemplate vaultTemplate; private final VaultTransitOperations transitOperations; private final Map keyValueOperationsMap; + private final KeyValueBackend keyValueBackend; /** * Creates a VaultCommunicationService that uses Spring Vault. @@ -60,6 +60,7 @@ public class StandardHashiCorpVaultCommunicationService implements HashiCorpVaul new SimpleSessionManager(vaultConfiguration.clientAuthentication())); transitOperations = vaultTemplate.opsForTransit(); + keyValueBackend = vaultConfiguration.getKeyValueBackend(); keyValueOperationsMap = new HashMap<>(); } @@ -94,7 +95,7 @@ public class StandardHashiCorpVaultCommunicationService implements HashiCorpVaul Objects.requireNonNull(secretKey, "Secret secretKey must be specified"); Objects.requireNonNull(value, "Secret value must be specified"); final VaultKeyValueOperations keyValueOperations = keyValueOperationsMap - .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, KV_1)); + .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, keyValueBackend)); keyValueOperations.put(secretKey, new SecretData(value)); } @@ -109,7 +110,7 @@ public class StandardHashiCorpVaultCommunicationService implements HashiCorpVaul Objects.requireNonNull(keyValuePath, "Vault K/V path must be specified"); Objects.requireNonNull(secretKey, "Secret secretKey must be specified"); final VaultKeyValueOperations keyValueOperations = keyValueOperationsMap - .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, KV_1)); + .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, keyValueBackend)); final VaultResponseSupport response = keyValueOperations.get(secretKey, SecretData.class); return response == null ? Optional.empty() : Optional.ofNullable(response.getRequiredData().getValue()); } @@ -123,14 +124,14 @@ public class StandardHashiCorpVaultCommunicationService implements HashiCorpVaul return; } final VaultKeyValueOperations keyValueOperations = keyValueOperationsMap - .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, KV_1)); + .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, keyValueBackend)); keyValueOperations.put(secretKey, keyValues); } @Override public Map readKeyValueSecretMap(final String keyValuePath, final String key) { final VaultKeyValueOperations keyValueOperations = keyValueOperationsMap - .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, KV_1)); + .computeIfAbsent(keyValuePath, path -> vaultTemplate.opsForKeyValue(path, keyValueBackend)); final VaultResponseSupport response = keyValueOperations.get(key, Map.class); return response == null ? Collections.emptyMap() : (Map) response.getRequiredData(); } diff --git a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultConfiguration.java b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultConfiguration.java index 34ce6c68a9..873477c097 100644 --- a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultConfiguration.java +++ b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.support.ResourcePropertySource; import org.springframework.vault.client.RestTemplateFactory; import org.springframework.vault.config.EnvironmentVaultConfiguration; +import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend; import org.springframework.vault.support.ClientOptions; import org.springframework.vault.support.SslConfiguration; @@ -37,10 +38,14 @@ import java.util.concurrent.TimeUnit; * A Vault configuration that uses the NiFiVaultEnvironment. */ public class HashiCorpVaultConfiguration extends EnvironmentVaultConfiguration { + private static final int KV_V1 = 1; + private static final int KV_V2 = 2; + public enum VaultConfigurationKey { AUTHENTICATION_PROPERTIES_FILE("vault.authentication.properties.file"), READ_TIMEOUT("vault.read.timeout"), CONNECTION_TIMEOUT("vault.connection.timeout"), + KV_VERSION("vault.kv.version"), URI("vault.uri"); private final String key; @@ -62,6 +67,7 @@ public class HashiCorpVaultConfiguration extends EnvironmentVaultConfiguration { private final SslConfiguration sslConfiguration; private final ClientOptions clientOptions; + private final KeyValueBackend keyValueBackend; /** * Creates a HashiCorpVaultConfiguration from property sources @@ -84,6 +90,22 @@ public class HashiCorpVaultConfiguration extends EnvironmentVaultConfiguration { } } + KeyValueBackend keyValueBackend = KeyValueBackend.KV_1; + if (env.containsProperty(VaultConfigurationKey.KV_VERSION.key)) { + final String kvVersion = env.getProperty(VaultConfigurationKey.KV_VERSION.key); + try { + int kvVersionNumber = Integer.parseInt(kvVersion); + if (kvVersionNumber == KV_V2) { + keyValueBackend = KeyValueBackend.KV_2; + } else if (kvVersionNumber != KV_V1) { + throw new IllegalArgumentException("K/V v" + kvVersion + " is not recognized"); + } + } catch (final IllegalArgumentException e) { + throw new HashiCorpVaultConfigurationException("Unrecognized " + VaultConfigurationKey.KV_VERSION.key + ": " + kvVersion, e); + } + } + this.keyValueBackend = keyValueBackend; + this.setApplicationContext(new HashiCorpVaultApplicationContext(env)); sslConfiguration = env.getProperty(VaultConfigurationKey.URI.key).contains(HTTPS) @@ -92,6 +114,10 @@ public class HashiCorpVaultConfiguration extends EnvironmentVaultConfiguration { clientOptions = getClientOptions(); } + public KeyValueBackend getKeyValueBackend() { + return keyValueBackend; + } + /** * A convenience method to create a PropertySource from a file on disk. * @param filename The properties filename. diff --git a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultProperties.java b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultProperties.java index 99b6ff13a9..5042dd3593 100644 --- a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultProperties.java +++ b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/HashiCorpVaultProperties.java @@ -38,26 +38,27 @@ public class HashiCorpVaultProperties { private final HashiCorpVaultSslProperties ssl; private final Optional connectionTimeout; private final Optional readTimeout; + private final int kvVersion; - private HashiCorpVaultProperties(final String uri, String keyStore, final String keyStoreType, final String keyStorePassword, final String trustStore, - final String trustStoreType, final String trustStorePassword, final String authPropertiesFilename, - final String enabledTlsCipherSuites, final String enabledTlsProtocols, final String connectionTimeout, final String readTimeout) { - Objects.requireNonNull(uri, "Vault URI is required"); - Objects.requireNonNull(authPropertiesFilename, "Vault auth properties filename is required"); - this.uri = uri; - this.authPropertiesFilename = authPropertiesFilename; - this.ssl = new HashiCorpVaultSslProperties(keyStore, keyStoreType, keyStorePassword, trustStore, trustStoreType, trustStorePassword, - enabledTlsCipherSuites, enabledTlsProtocols); - this.connectionTimeout = connectionTimeout == null ? Optional.empty() : Optional.of(connectionTimeout); - this.readTimeout = readTimeout == null ? Optional.empty() : Optional.of(readTimeout); + private HashiCorpVaultProperties(final HashiCorpVaultPropertiesBuilder builder) { + this.uri = Objects.requireNonNull(builder.uri, "Vault URI is required");; + this.authPropertiesFilename = Objects.requireNonNull(builder.authPropertiesFilename, "Vault auth properties filename is required"); + this.ssl = new HashiCorpVaultSslProperties(builder.keyStore, builder.keyStoreType, builder.keyStorePassword, + builder.trustStore, builder.trustStoreType, builder.trustStorePassword,builder.enabledTlsCipherSuites, builder.enabledTlsProtocols); + this.connectionTimeout = builder.connectionTimeout == null ? Optional.empty() : Optional.of(builder.connectionTimeout); + this.readTimeout = builder.readTimeout == null ? Optional.empty() : Optional.of(builder.readTimeout); + this.kvVersion = builder.kvVersion; + if (kvVersion != 1 && kvVersion != 2) { + throw new HashiCorpVaultConfigurationException("Key/Value version " + kvVersion + " is not supported"); + } if (uri.startsWith(HTTPS)) { - Objects.requireNonNull(keyStore, "KeyStore is required with an https URI"); - Objects.requireNonNull(keyStorePassword, "KeyStore password is required with an https URI"); - Objects.requireNonNull(keyStoreType, "KeyStore type is required with an https URI"); - Objects.requireNonNull(trustStore, "TrustStore is required with an https URI"); - Objects.requireNonNull(trustStorePassword, "TrustStore password is required with an https URI"); - Objects.requireNonNull(trustStoreType, "TrustStore type is required with an https URI"); + Objects.requireNonNull(builder.keyStore, "KeyStore is required with an https URI"); + Objects.requireNonNull(builder.keyStorePassword, "KeyStore password is required with an https URI"); + Objects.requireNonNull(builder.keyStoreType, "KeyStore type is required with an https URI"); + Objects.requireNonNull(builder.trustStore, "TrustStore is required with an https URI"); + Objects.requireNonNull(builder.trustStorePassword, "TrustStore password is required with an https URI"); + Objects.requireNonNull(builder.trustStoreType, "TrustStore type is required with an https URI"); } validateAuthProperties(); } @@ -79,6 +80,11 @@ public class HashiCorpVaultProperties { return ssl; } + @HashiCorpVaultProperty(key = "kv.version") + public int getKvVersion() { + return kvVersion; + } + @HashiCorpVaultProperty(key = "authentication.properties.file") public String getAuthPropertiesFilename() { return authPropertiesFilename; @@ -108,6 +114,7 @@ public class HashiCorpVaultProperties { private String enabledTlsProtocols; private String connectionTimeout; private String readTimeout; + private int kvVersion = 1; /** * Set the Vault URI (e.g., http://localhost:8200). If using https protocol, the KeyStore and TrustStore @@ -120,6 +127,16 @@ public class HashiCorpVaultProperties { return this; } + /** + * Sets the Key/Value secrets engine version (1 or 2). + * @param kvVersion The Key/Value engine version + * @return Builder + */ + public HashiCorpVaultPropertiesBuilder setKvVersion(int kvVersion) { + this.kvVersion = kvVersion; + return this; + } + /** * Sets the path to the keyStore. * @param keyStore Path to the keyStore @@ -240,8 +257,7 @@ public class HashiCorpVaultProperties { * @return Builder */ public HashiCorpVaultProperties build() { - return new HashiCorpVaultProperties(uri, keyStore, keyStoreType, keyStorePassword, trustStore, trustStoreType, - trustStorePassword, authPropertiesFilename, enabledTlsCipherSuites, enabledTlsProtocols, connectionTimeout, readTimeout); + return new HashiCorpVaultProperties(this); } } } diff --git a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/lookup/BeanPropertyLookup.java b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/lookup/BeanPropertyLookup.java index da873afa24..1b7bab2a33 100644 --- a/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/lookup/BeanPropertyLookup.java +++ b/nifi-commons/nifi-vault-utils/src/main/java/org/apache/nifi/vault/hashicorp/config/lookup/BeanPropertyLookup.java @@ -44,11 +44,16 @@ public class BeanPropertyLookup extends PropertyLookup { .filter(pd -> pd.getReadMethod().getAnnotation(HashiCorpVaultProperty.class) != null) .collect(Collectors.toMap( pd -> getPropertyKey(prefix, pd), - pd -> pd.getReadMethod().getReturnType().equals(String.class) ? new ValuePropertyLookup(pd) + pd -> isValueProperty(pd) ? new ValuePropertyLookup(pd) : new BeanPropertyLookup(getPropertyKey(prefix, pd), pd.getReadMethod().getReturnType(), pd) )); } + private boolean isValueProperty(final PropertyDescriptor propertyDescriptor) { + final Class returnType = propertyDescriptor.getReadMethod().getReturnType(); + return returnType.equals(String.class) || returnType.isPrimitive(); + } + private static String getPropertyKey(final String prefix, final PropertyDescriptor propertyDescriptor) { final HashiCorpVaultProperty propertyAnnotation = propertyDescriptor.getReadMethod().getAnnotation(HashiCorpVaultProperty.class); final String unqualifiedPropertyKey = !propertyAnnotation.key().isEmpty() ? propertyAnnotation.key() : propertyDescriptor.getDisplayName(); diff --git a/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationServiceIT.java b/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationServiceIT.java index 6261376dcd..2080e147a8 100644 --- a/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationServiceIT.java +++ b/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/StandardHashiCorpVaultCommunicationServiceIT.java @@ -32,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; * vault server -dev * vault secrets enable transit * vault secrets enable kv + * vault secrets enable kv-v2 * vault write -f transit/keys/nifi * * Make note of the Root Token and create a properties file with the contents: @@ -48,10 +49,13 @@ public class StandardHashiCorpVaultCommunicationServiceIT { @BeforeEach public void init() { - vcs = new StandardHashiCorpVaultCommunicationService(new HashiCorpVaultProperties.HashiCorpVaultPropertiesBuilder() + vcs = new StandardHashiCorpVaultCommunicationService(defaultServiceBuilder().build()); + } + + private HashiCorpVaultProperties.HashiCorpVaultPropertiesBuilder defaultServiceBuilder() { + return new HashiCorpVaultProperties.HashiCorpVaultPropertiesBuilder() .setAuthPropertiesFilename(System.getProperty("vault.auth.properties")) - .setUri("http://127.0.0.1:8200") - .build()); + .setUri("http://127.0.0.1:8200"); } @Test @@ -83,6 +87,22 @@ public class StandardHashiCorpVaultCommunicationServiceIT { assertEquals(value, resultValue); } + /** + * Run vault kv get kv_v2/key to see the secret + */ + @Test + public void testReadWriteSecret_kv_v2() { + final String key = "key"; + final String value = "value"; + + vcs = new StandardHashiCorpVaultCommunicationService(defaultServiceBuilder().setKvVersion(2).build()); + + vcs.writeKeyValueSecret("kv-v2", key, value); + + final String resultValue = vcs.readKeyValueSecret("kv-v2", key).orElseThrow(() -> new NullPointerException("Missing secret for kv/key")); + assertEquals(value, resultValue); + } + /** * Run vault kv get kv/secret to see the secret */ diff --git a/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestHashiCorpVaultConfiguration.java b/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestHashiCorpVaultConfiguration.java index 9dd75f9b6f..190b9aa6ce 100644 --- a/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestHashiCorpVaultConfiguration.java +++ b/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestHashiCorpVaultConfiguration.java @@ -25,6 +25,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.vault.authentication.ClientAuthentication; import org.springframework.vault.client.VaultEndpoint; +import org.springframework.vault.core.VaultKeyValueOperationsSupport; import org.springframework.vault.support.SslConfiguration; import java.io.File; @@ -134,6 +135,29 @@ public class TestHashiCorpVaultConfiguration { this.runTest("http"); } + @Test + public void testKvVersion() { + config = new HashiCorpVaultConfiguration(new HashiCorpVaultPropertySource(propertiesBuilder.build())); + assertEquals(VaultKeyValueOperationsSupport.KeyValueBackend.KV_1, config.getKeyValueBackend()); + + propertiesBuilder.setKvVersion(2); + config = new HashiCorpVaultConfiguration(new HashiCorpVaultPropertySource(propertiesBuilder.build())); + assertEquals(VaultKeyValueOperationsSupport.KeyValueBackend.KV_2, config.getKeyValueBackend()); + + propertiesBuilder.setKvVersion(1); + config = new HashiCorpVaultConfiguration(new HashiCorpVaultPropertySource(propertiesBuilder.build())); + assertEquals(VaultKeyValueOperationsSupport.KeyValueBackend.KV_1, config.getKeyValueBackend()); + } + + @Test + public void testKvVersionInvalid() { + propertiesBuilder.setKvVersion(0); + assertThrows(HashiCorpVaultConfigurationException.class, () -> new HashiCorpVaultConfiguration(new HashiCorpVaultPropertySource(propertiesBuilder.build()))); + + propertiesBuilder.setKvVersion(3); + assertThrows(HashiCorpVaultConfigurationException.class, () -> new HashiCorpVaultConfiguration(new HashiCorpVaultPropertySource(propertiesBuilder.build()))); + } + @Test public void testTlsProperties() throws IOException { propertiesBuilder.setKeyStore(keystoreFile.toFile().getAbsolutePath()); diff --git a/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestStandardHashiCorpVaultCommunicationService.java b/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestStandardHashiCorpVaultCommunicationService.java index 4eb14eb79d..a24f13b28d 100644 --- a/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestStandardHashiCorpVaultCommunicationService.java +++ b/nifi-commons/nifi-vault-utils/src/test/java/org/apache/nifi/vault/hashicorp/TestStandardHashiCorpVaultCommunicationService.java @@ -32,6 +32,8 @@ import java.util.Arrays; import java.util.Optional; import java.util.stream.Collectors; +import static org.mockito.Mockito.when; + public class TestStandardHashiCorpVaultCommunicationService { public static final String URI_VALUE = "http://127.0.0.1:8200"; public static final String CIPHER_SUITE_VALUE = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; @@ -47,9 +49,10 @@ public class TestStandardHashiCorpVaultCommunicationService { properties = Mockito.mock(HashiCorpVaultProperties.class); sslProperties = Mockito.mock(HashiCorpVaultSslProperties.class); - Mockito.when(properties.getUri()).thenReturn(URI_VALUE); - Mockito.when(properties.getAuthPropertiesFilename()).thenReturn(authProps.getAbsolutePath()); - Mockito.when(properties.getSsl()).thenReturn(sslProperties); + when(properties.getUri()).thenReturn(URI_VALUE); + when(properties.getAuthPropertiesFilename()).thenReturn(authProps.getAbsolutePath()); + when(properties.getSsl()).thenReturn(sslProperties); + when(properties.getKvVersion()).thenReturn(1); } @AfterEach @@ -88,8 +91,8 @@ public class TestStandardHashiCorpVaultCommunicationService { @Test public void testTimeouts() { - Mockito.when(properties.getConnectionTimeout()).thenReturn(Optional.of("20 secs")); - Mockito.when(properties.getReadTimeout()).thenReturn(Optional.of("40 secs")); + when(properties.getConnectionTimeout()).thenReturn(Optional.of("20 secs")); + when(properties.getReadTimeout()).thenReturn(Optional.of("40 secs")); this.configureService(); } @@ -97,17 +100,17 @@ public class TestStandardHashiCorpVaultCommunicationService { public void testTLS() { TlsConfiguration tlsConfiguration = new TemporaryKeyStoreBuilder().build(); - Mockito.when(sslProperties.getKeyStore()).thenReturn(tlsConfiguration.getKeystorePath()); - Mockito.when(sslProperties.getKeyStorePassword()).thenReturn(tlsConfiguration.getKeystorePassword()); - Mockito.when(sslProperties.getKeyStoreType()).thenReturn(tlsConfiguration.getKeystoreType().getType()); - Mockito.when(sslProperties.getTrustStore()).thenReturn(tlsConfiguration.getTruststorePath()); - Mockito.when(sslProperties.getTrustStorePassword()).thenReturn(tlsConfiguration.getTruststorePassword()); - Mockito.when(sslProperties.getTrustStoreType()).thenReturn(tlsConfiguration.getTruststoreType().getType()); - Mockito.when(sslProperties.getEnabledProtocols()).thenReturn(Arrays.stream(tlsConfiguration.getEnabledProtocols()) + when(sslProperties.getKeyStore()).thenReturn(tlsConfiguration.getKeystorePath()); + when(sslProperties.getKeyStorePassword()).thenReturn(tlsConfiguration.getKeystorePassword()); + when(sslProperties.getKeyStoreType()).thenReturn(tlsConfiguration.getKeystoreType().getType()); + when(sslProperties.getTrustStore()).thenReturn(tlsConfiguration.getTruststorePath()); + when(sslProperties.getTrustStorePassword()).thenReturn(tlsConfiguration.getTruststorePassword()); + when(sslProperties.getTrustStoreType()).thenReturn(tlsConfiguration.getTruststoreType().getType()); + when(sslProperties.getEnabledProtocols()).thenReturn(Arrays.stream(tlsConfiguration.getEnabledProtocols()) .collect(Collectors.joining(","))); - Mockito.when(sslProperties.getEnabledCipherSuites()).thenReturn(CIPHER_SUITE_VALUE); + when(sslProperties.getEnabledCipherSuites()).thenReturn(CIPHER_SUITE_VALUE); - Mockito.when(properties.getUri()).thenReturn(URI_VALUE.replace("http", "https")); + when(properties.getUri()).thenReturn(URI_VALUE.replace("http", "https")); this.configureService(); this.ensureTlsPropertiesAccessed(1); diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc index dda5ef3e84..d61b2134ef 100644 --- a/nifi-docs/src/main/asciidoc/administration-guide.adoc +++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc @@ -1852,6 +1852,7 @@ Following are the configuration properties available inside the `bootstrap-hashi [options="header,footer"] |=== |Property Name|Description|Default +|`vault.kv.version`|The Key/Value Secrets Engine version: `1` for unversioned, and `2` for versioned. This must match the versioned enabled in Vault.|`1` |`vault.connection.timeout`|The connection timeout of the Vault client|`5 secs` |`vault.read.timeout`|The read timeout of the Vault client|`15 secs` |`vault.ssl.enabledCipherSuites`|A comma-separated list of the enabled TLS cipher suites|_none_ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf index bbf54f57cf..bf6975b962 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf @@ -23,6 +23,8 @@ vault.transit.path= # Key/Value Path is required to enable the Sensitive Properties Provider Protection Scheme 'hashicorp/vault/kv/{path}' vault.kv.path= +# Key/Value Secrets Engine version may be 1 or 2, and defaults to 1 +# vault.kv.version=1 # Token Authentication example properties # vault.authentication=TOKEN diff --git a/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf b/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf index bbf54f57cf..bf6975b962 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf +++ b/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf @@ -23,6 +23,8 @@ vault.transit.path= # Key/Value Path is required to enable the Sensitive Properties Provider Protection Scheme 'hashicorp/vault/kv/{path}' vault.kv.path= +# Key/Value Secrets Engine version may be 1 or 2, and defaults to 1 +# vault.kv.version=1 # Token Authentication example properties # vault.authentication=TOKEN