From 00fb2ca961eae78ad6a508d0e0398351d482bcdb Mon Sep 17 00:00:00 2001 From: Sergey Ripa Date: Thu, 21 May 2020 15:38:56 +0200 Subject: [PATCH 1/3] Support multiple vault path-s in Vault config source --- .../config/vault/VaultConfigSource.java | 56 +++++++++++-------- .../config/vault/VaultConfigSourceTest.java | 29 +++++++++- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java b/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java index e331ee4b..5cbf8211 100644 --- a/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java +++ b/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java @@ -7,6 +7,10 @@ import io.scalecube.config.ConfigSourceNotAvailableException; import io.scalecube.config.source.ConfigSource; import io.scalecube.config.source.LoadedConfigProperty; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Function; @@ -27,31 +31,35 @@ public class VaultConfigSource implements ConfigSource { private static final String VAULT_SECRETS_PATH = "VAULT_SECRETS_PATH"; private final VaultInvoker vault; - private final String secretsPath; + private final List secretsPath; /** * Create a new {@link VaultConfigSource}. - * - * @param vault vault invoker. - * @param secretsPath secret path. + * @param vault vault invoker. + * @param secretsPaths secret path-s. */ - private VaultConfigSource(VaultInvoker vault, String secretsPath) { + private VaultConfigSource(VaultInvoker vault, List secretsPaths) { this.vault = vault; - this.secretsPath = secretsPath; + this.secretsPath = secretsPaths; } @Override public Map loadConfig() { - try { - LogicalResponse response = vault.invoke(vault -> vault.logical().read(secretsPath)); - return response.getData().entrySet().stream() - .map(LoadedConfigProperty::withNameAndValue) - .map(LoadedConfigProperty.Builder::build) - .collect(Collectors.toMap(LoadedConfigProperty::name, Function.identity())); - } catch (Exception ex) { - LOGGER.warn("unable to load config properties", ex); - throw new ConfigSourceNotAvailableException(ex); + Map result = new HashMap<>(); + for (String path : secretsPath) { + try { + LogicalResponse response = vault.invoke(vault -> vault.logical().read(path)); + final Map pathProps = response.getData().entrySet().stream() + .map(LoadedConfigProperty::withNameAndValue) + .map(LoadedConfigProperty.Builder::build) + .collect(Collectors.toMap(LoadedConfigProperty::name, Function.identity())); + result.putAll(pathProps); + } catch (Exception ex) { + LOGGER.warn("unable to load config properties", ex); + throw new ConfigSourceNotAvailableException(ex); + } } + return result; } /** @@ -87,12 +95,12 @@ public static final class Builder { private Function vault = Function.identity(); private VaultInvoker invoker; private EnvironmentLoader environmentLoader = VaultInvoker.Builder.ENVIRONMENT_LOADER; - private String secretsPath; + private List secretsPaths = new ArrayList<>(); private Builder() {} public Builder secretsPath(String secretsPath) { - this.secretsPath = secretsPath; + this.secretsPaths.add(secretsPath); return this; } @@ -126,13 +134,13 @@ public VaultConfigSource build() { invoker != null ? invoker : vault.apply(new VaultInvoker.Builder(environmentLoader)).build(); - secretsPath = - Objects.requireNonNull( - secretsPath != null - ? secretsPath - : environmentLoader.loadVariable(VAULT_SECRETS_PATH), - "Missing secretsPath"); - return new VaultConfigSource(vaultInvoker, secretsPath); + if (secretsPaths.isEmpty()) { + String envSecretPath = Objects + .requireNonNull(environmentLoader.loadVariable(VAULT_SECRETS_PATH), + "Missing secretsPath"); + secretsPaths = Arrays.asList(envSecretPath.split(":")); + } + return new VaultConfigSource(vaultInvoker, secretsPaths); } } } diff --git a/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java b/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java index 4f8a511f..1be3643b 100644 --- a/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java +++ b/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java @@ -49,9 +49,9 @@ class VaultConfigSourceTest { static void beforeAll() { VaultInstance vaultInstance = vaultContainerExtension.vaultInstance(); vaultInstance.putSecrets( - VAULT_SECRETS_PATH1, "top_secret=password1", "db_password=dbpassword1"); + VAULT_SECRETS_PATH1, "top_secret=password1", "db_password=dbpassword1", "only_first=pss1"); vaultInstance.putSecrets( - VAULT_SECRETS_PATH2, "top_secret=password2", "db_password=dbpassword2"); + VAULT_SECRETS_PATH2, "top_secret=password2", "db_password=dbpassword2", "only_second=pss2"); vaultInstance.putSecrets(VAULT_SECRETS_PATH3, "secret=password", "password=dbpassword"); } @@ -88,6 +88,31 @@ void testSecondTenant() { assertThat(actual.valueAsString(""), equalTo("password2")); } + @Test + void testMultiplePathsEnv() { + String commonPath = VAULT_SECRETS_PATH1 + ":" + VAULT_SECRETS_PATH2; + EnvironmentLoader multiLoader = + new MockEnvironmentLoader(baseLoader).put(VAULT_SECRETS_PATH, commonPath); + VaultConfigSource vaultConfigSource = VaultConfigSource.builder(multiLoader).build(); + Map loadConfig = vaultConfigSource.loadConfig(); + + ConfigProperty commonSecret = loadConfig.get("top_secret"); + assertThat(commonSecret, notNullValue()); + assertThat(commonSecret.name(), equalTo("top_secret")); + assertThat("Second path should override the first one", commonSecret.valueAsString(""), + equalTo("password2")); + + ConfigProperty fromFirstPath = loadConfig.get("only_first"); + assertThat(commonSecret.name(), equalTo("only_first")); + assertThat("Secret defined only in first path expected", fromFirstPath.valueAsString(""), + equalTo("pss1")); + + ConfigProperty fromSecondPath = loadConfig.get("only_second"); + assertThat(commonSecret.name(), equalTo("only_second")); + assertThat("Secret defined only in second path expected", fromFirstPath.valueAsString(""), + equalTo("pss2")); + } + @Test void testMissingProperty() { VaultConfigSource vaultConfigSource = VaultConfigSource.builder(loader3).build(); From 420f246be1321a5445f6cbc0a4544db765e713c7 Mon Sep 17 00:00:00 2001 From: Sergey Ripa Date: Thu, 21 May 2020 16:05:05 +0200 Subject: [PATCH 2/3] fix test --- .../io/scalecube/config/vault/VaultConfigSourceTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java b/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java index 1be3643b..5b277ba3 100644 --- a/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java +++ b/config-vault/src/test/java/io/scalecube/config/vault/VaultConfigSourceTest.java @@ -103,13 +103,13 @@ void testMultiplePathsEnv() { equalTo("password2")); ConfigProperty fromFirstPath = loadConfig.get("only_first"); - assertThat(commonSecret.name(), equalTo("only_first")); + assertThat(fromFirstPath.name(), equalTo("only_first")); assertThat("Secret defined only in first path expected", fromFirstPath.valueAsString(""), equalTo("pss1")); ConfigProperty fromSecondPath = loadConfig.get("only_second"); - assertThat(commonSecret.name(), equalTo("only_second")); - assertThat("Secret defined only in second path expected", fromFirstPath.valueAsString(""), + assertThat(fromSecondPath.name(), equalTo("only_second")); + assertThat("Secret defined only in second path expected", fromSecondPath.valueAsString(""), equalTo("pss2")); } From 6670df21a4119d18e381859739712cecc676c67f Mon Sep 17 00:00:00 2001 From: Sergey Ripa Date: Thu, 21 May 2020 16:33:00 +0200 Subject: [PATCH 3/3] improve log --- .../main/java/io/scalecube/config/vault/VaultConfigSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java b/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java index 5cbf8211..245c5fa7 100644 --- a/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java +++ b/config-vault/src/main/java/io/scalecube/config/vault/VaultConfigSource.java @@ -55,7 +55,7 @@ public Map loadConfig() { .collect(Collectors.toMap(LoadedConfigProperty::name, Function.identity())); result.putAll(pathProps); } catch (Exception ex) { - LOGGER.warn("unable to load config properties", ex); + LOGGER.warn("unable to load config properties from {}",path, ex); throw new ConfigSourceNotAvailableException(ex); } }