Uses label when searching secrets in [Spring]VaultEnvironmentRepository (#2460)

* Uses label when searching secrets in [Spring]VaultEnvironmentRepository

Signed-off-by: kvmw <mshamsi@broadcom.com>

* Adds a feature flag to enable label in vault secret paths

Signed-off-by: kvmw <mshamsi@broadcom.com>

* Makes default-label in [Spring]VaultEnvironmentRepository configurable

Signed-off-by: kvmw <mshamsi@broadcom.com>

* When label flag is enabled, profile should always by included in vault key

Signed-off-by: kvmw <mshamsi@broadcom.com>

* Updates Vault docs

Signed-off-by: kvmw <mshamsi@broadcom.com>

* Switches to main as default label for vault

Signed-off-by: kvmw <mshamsi@broadcom.com>

---------

Signed-off-by: kvmw <mshamsi@broadcom.com>
This commit is contained in:
Kaveh Shamsi
2024-10-09 16:55:29 +02:00
committed by GitHub
parent e464808fa3
commit 6914dc89b1
6 changed files with 501 additions and 87 deletions

View File

@@ -16,11 +16,12 @@
package org.springframework.cloud.config.server.environment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotEmpty;
@@ -33,6 +34,7 @@ import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.core.Ordered;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import static org.springframework.cloud.config.client.ConfigClientProperties.STATE_HEADER;
@@ -46,7 +48,9 @@ import static org.springframework.cloud.config.client.ConfigClientProperties.STA
*/
public abstract class AbstractVaultEnvironmentRepository implements EnvironmentRepository, Ordered {
private static Log log = LogFactory.getLog(AbstractVaultEnvironmentRepository.class);
private static final String DEFAULT_PROFILE = "default";
private static final Log log = LogFactory.getLog(AbstractVaultEnvironmentRepository.class);
// TODO: move to watchState:String on findOne?
protected final ObjectProvider<HttpServletRequest> request;
@@ -65,12 +69,18 @@ public abstract class AbstractVaultEnvironmentRepository implements EnvironmentR
@NotEmpty
protected String profileSeparator;
protected final boolean enableLabel;
protected final String defaultLabel;
protected int order;
public AbstractVaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
VaultEnvironmentProperties properties) {
this.defaultKey = properties.getDefaultKey();
this.profileSeparator = properties.getProfileSeparator();
this.enableLabel = properties.isEnableLabel();
this.defaultLabel = properties.getDefaultLabel();
this.order = properties.getOrder();
this.request = request;
this.watch = watch;
@@ -78,24 +88,32 @@ public abstract class AbstractVaultEnvironmentRepository implements EnvironmentR
@Override
public Environment findOne(String application, String profile, String label) {
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
List<String> scrubbedProfiles = scrubProfiles(profiles);
if (ObjectUtils.isEmpty(profile)) {
profile = DEFAULT_PROFILE;
}
if (ObjectUtils.isEmpty(label)) {
label = defaultLabel;
}
List<String> keys = findKeys(application, scrubbedProfiles);
var environment = new Environment(application, split(profile), label, null, getWatchState());
Environment environment = new Environment(application, profiles, label, null, getWatchState());
var profiles = normalize(profile, DEFAULT_PROFILE);
var applications = normalize(application, this.defaultKey);
for (String key : keys) {
// read raw 'data' key from vault
String data = read(key);
if (data != null) {
// data is in json format of which, yaml is a superset, so parse
final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ByteArrayResource(data.getBytes()));
Properties properties = yaml.getObject();
for (String prof : profiles) {
for (String app : applications) {
var key = vaultKey(app, prof, label);
// read raw 'data' key from vault
String data = read(key);
if (data != null) {
// data is in json format of which, yaml is a superset, so parse
var yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ByteArrayResource(data.getBytes()));
var properties = yaml.getObject();
if (!properties.isEmpty()) {
environment.add(new PropertySource("vault:" + key, properties));
if (properties != null && !properties.isEmpty()) {
environment.add(new PropertySource("vault:" + key, properties));
}
}
}
}
@@ -105,6 +123,22 @@ public abstract class AbstractVaultEnvironmentRepository implements EnvironmentR
protected abstract String read(String key);
private String vaultKey(String application, String profile, String label) {
var key = application;
if (this.enableLabel) {
// always append profile to the key, if flag is enabled.
key += this.profileSeparator + profile;
// always append label to the key, if flag is enabled.
key += this.profileSeparator + label;
}
else if (!DEFAULT_PROFILE.equals(profile)) {
// default profile should not be included in the key, if flag is not enabled.
key += this.profileSeparator + profile;
}
return key;
}
private String getWatchState() {
HttpServletRequest servletRequest = this.request.getIfAvailable();
if (servletRequest != null) {
@@ -120,35 +154,22 @@ public abstract class AbstractVaultEnvironmentRepository implements EnvironmentR
return null;
}
private List<String> findKeys(String application, List<String> profiles) {
List<String> keys = new ArrayList<>();
/**
* Splits the comma delimited items and returns the reversed distinct items with given
* default item at the end.
*/
private List<String> normalize(String commaDelimitedItems, String defaultItem) {
var items = Stream.concat(Stream.of(defaultItem), Arrays.stream(split(commaDelimitedItems)))
.distinct()
.filter(Predicate.not(ObjectUtils::isEmpty))
.collect(Collectors.toList());
if (StringUtils.hasText(this.defaultKey) && !this.defaultKey.equals(application)) {
keys.add(this.defaultKey);
addProfiles(keys, this.defaultKey, profiles);
}
// application may have comma-separated list of names
String[] applications = StringUtils.commaDelimitedListToStringArray(application);
for (String app : applications) {
keys.add(app);
addProfiles(keys, app, profiles);
}
Collections.reverse(keys);
return keys;
Collections.reverse(items);
return items;
}
private List<String> scrubProfiles(String[] profiles) {
List<String> scrubbedProfiles = new ArrayList<>(Arrays.asList(profiles));
scrubbedProfiles.remove("default");
return scrubbedProfiles;
}
private void addProfiles(List<String> contexts, String baseContext, List<String> profiles) {
for (String profile : profiles) {
contexts.add(baseContext + this.profileSeparator + profile);
}
private String[] split(String str) {
return StringUtils.commaDelimitedListToStringArray(str);
}
public void setDefaultKey(String defaultKey) {

View File

@@ -101,6 +101,17 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp
*/
private String token;
/**
* Flag to indicate that the repository should use 'label' as well as
* 'application-name' and 'profile', for vault secrets. By default, the vault secrets
* are expected to be in 'application-name,profile' path. When this flag enabled, they
* are expected to be in `application-name,profile,label' path. To maintain
* compatibility this flag is not enabled by default.
*/
private boolean enableLabel = false;
private String defaultLabel = "main";
private AppRoleProperties appRole = new AppRoleProperties();
private AwsEc2Properties awsEc2 = new AwsEc2Properties();
@@ -229,6 +240,22 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp
this.token = token;
}
public boolean isEnableLabel() {
return enableLabel;
}
public void setEnableLabel(boolean enableLabel) {
this.enableLabel = enableLabel;
}
public String getDefaultLabel() {
return defaultLabel;
}
public void setDefaultLabel(String defaultLabel) {
this.defaultLabel = defaultLabel;
}
public AppRoleProperties getAppRole() {
return this.appRole;
}

View File

@@ -23,7 +23,6 @@ import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@@ -57,12 +56,8 @@ public class VaultEnvironmentRepositoryTests {
@SuppressWarnings("unchecked")
ArgumentCaptor<HttpEntity<?>> requestHeaderCaptor = ArgumentCaptor.forClass(HttpEntity.class);
@BeforeEach
public void init() {
}
@Test
public void testFindOneNoDefaultKey() {
public void findOneWithNoDefaultKey() {
stubRestTemplate("secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/application", toEntityResponse("def-foo", "def-bar"));
@@ -71,14 +66,33 @@ public class VaultEnvironmentRepositoryTests {
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
assertThat(requestHeaderCaptor.getValue().getHeaders()).containsEntry("X-Vault-Token", List.of("token"));
}
@Test
public void testBackendWithSlashes() {
public void findOneWithEmptyDefaultKey() {
stubRestTemplate("secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/application", toEntityResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setDefaultKey("");
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, "my-label");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(1);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
}
@Test
public void findOneWithSlashesInBackend() {
stubRestTemplate("foo/bar/secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("foo/bar/secret/application", toEntityResponse("def-foo", "def-bar"));
@@ -90,12 +104,14 @@ public class VaultEnvironmentRepositoryTests {
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void testFindOneDefaultKeySetAndDifferentToApplication() {
public void findOneWithDefaultKeySet() {
stubRestTemplate("secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/mydefaultkey", toEntityResponse("def-foo", "def-bar"));
@@ -107,12 +123,14 @@ public class VaultEnvironmentRepositoryTests {
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:mydefaultkey");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void testFindOneDefaultKeySetAndDifferentToMultipleApplications() {
public void findOneWithDefaultKeyAndMultipleApplicationNames() {
stubRestTemplate("secret/myapp", toEntityResponse("myapp-foo", "myapp-bar"));
stubRestTemplate("secret/yourapp", toEntityResponse("yourapp-foo", "yourapp-bar"));
stubRestTemplate("secret/mydefaultkey", toEntityResponse("def-foo", "def-bar"));
@@ -126,28 +144,82 @@ public class VaultEnvironmentRepositoryTests {
assertThat(e.getPropertySources().size()).isEqualTo(3);
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("yourapp-foo", "yourapp-bar"));
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:yourapp");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("myapp-foo", "myapp-bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:mydefaultkey");
}
@Test
public void testFindOneDefaultKeySetAndEqualToApplication() {
public void findOneWithDefaultKeySetToApplicationName() {
stubRestTemplate("secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/application", toEntityResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setDefaultKey("myapp");
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, null);
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, "lbl");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(1);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
}
@Test
public void missingConfigToken() {
public void findOneWithProfile() {
stubRestTemplate("secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/myapp,my-profile", toEntityResponse("pro-foo", "pro-bar"));
stubRestTemplate("secret/application", toEntityResponse("def-foo", "def-bar"));
stubRestTemplate("secret/application,my-profile", toEntityResponse("def-pro-foo", "def-pro-bar"));
var e = vaultEnvironmentRepository().findOne("myapp", "my-profile", "lbl");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(4);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,my-profile");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("pro-foo", "pro-bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,my-profile");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-pro-foo", "def-pro-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(3).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(3).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithMultipleProfiles() {
stubRestTemplate("secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/myapp,pr1", toEntityResponse("pr1-foo", "pr1-bar"));
stubRestTemplate("secret/myapp,pr2", toEntityResponse("pr2-foo", "pr2-bar"));
stubRestTemplate("secret/application", toEntityResponse("def-foo", "def-bar"));
stubRestTemplate("secret/application,pr1", toEntityResponse("def-pr1-foo", "def-pr1-bar"));
stubRestTemplate("secret/application,pr2", toEntityResponse("def-pr2-foo", "def-pr2-bar"));
var e = vaultEnvironmentRepository().findOne("myapp", "pr1,pr2", null);
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(6);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,pr2");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("pr2-foo", "pr2-bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,pr2");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-pr2-foo", "def-pr2-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:myapp,pr1");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("pr1-foo", "pr1-bar"));
assertThat(e.getPropertySources().get(3).getName()).isEqualTo("vault:application,pr1");
assertThat(e.getPropertySources().get(3).getSource()).isEqualTo(Map.of("def-pr1-foo", "def-pr1-bar"));
assertThat(e.getPropertySources().get(4).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(4).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(5).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(5).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWhenConfigTokenIsMissing() {
ConfigTokenProvider nullTokenProvider = () -> null;
Assertions.assertThatThrownBy(() -> vaultEnvironmentRepository(nullTokenProvider).findOne("myapp", null, null))
@@ -155,25 +227,28 @@ public class VaultEnvironmentRepositoryTests {
}
@Test
public void testVaultVersioning() {
public void findOneWithVaultVersioning() {
stubRestTemplate("secret/data/myapp", toEntityResponse("data", Map.of("foo", "bar")));
stubRestTemplate("secret/data/application", toEntityResponse("data", Map.of("def-foo", "def-bar")));
var properties = new VaultEnvironmentProperties();
properties.setKvVersion(2);
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, null);
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, "label");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
assertThat(requestHeaderCaptor.getValue().getHeaders()).containsEntry("X-Vault-Token", List.of("token"));
}
@Test
public void testVaultKV2WithPath2Key() {
public void findOneWithVaultKV2WithPath2Key() {
stubRestTemplate("secret/data/myorg/myapp", toEntityResponse("data", Map.of("foo", "bar")));
stubRestTemplate("secret/data/myorg/application", toEntityResponse("data", Map.of("def-foo", "def-bar")));
@@ -181,26 +256,112 @@ public class VaultEnvironmentRepositoryTests {
properties.setKvVersion(2);
properties.setPathToKey("myorg");
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, null);
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, "lbl");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void testNamespaceHeaderSent() {
public void findOneWithNamespaceHeaderSent() {
stubRestTemplate("secret/myapp", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/application", toEntityResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setNamespace("mynamespace");
vaultEnvironmentRepository(properties).findOne("myapp", null, null);
vaultEnvironmentRepository(properties).findOne("myapp", null, "lbl");
assertThat(requestHeaderCaptor.getValue().getHeaders()).containsEntry("X-Vault-Namespace",
List.of("mynamespace"));
assertThat(requestHeaderCaptor.getValue().getHeaders()).containsEntry("X-Vault-Token", List.of("token"));
}
@Test
public void findOneWithDefaultLabelWhenLabelEnabled() {
stubRestTemplate("secret/myapp,default,main", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/application,default,main", toEntityResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, null);
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,default,main");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,default,main");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithCustomDefaultLabelWhenLabelEnabled() {
stubRestTemplate("secret/myapp,default,custom", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/application,default,custom", toEntityResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
properties.setDefaultLabel("custom");
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, null);
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,default,custom");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,default,custom");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithCustomLabelWhenLabelEnabled() {
stubRestTemplate("secret/myapp,default,my-label", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/application,default,my-label", toEntityResponse(Map.of()));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
properties.setDefaultLabel("custom");
var e = vaultEnvironmentRepository(properties).findOne("myapp", null, "my-label");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(1);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,default,my-label");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
}
@Test
public void findOneWithCustomLabelAndProfileWhenLabelEnabled() {
stubRestTemplate("secret/myapp,default,my-label", toEntityResponse("foo", "bar"));
stubRestTemplate("secret/myapp,pr1,my-label", toEntityResponse("pr1-foo", "pr1-bar"));
stubRestTemplate("secret/application,default,my-label", toEntityResponse("def-foo", "def-bar"));
stubRestTemplate("secret/application,pr1,my-label", toEntityResponse("def-pr1-foo", "def-pr1-bar"));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
var e = vaultEnvironmentRepository(properties).findOne("myapp", "pr1", "my-label");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources().size()).isEqualTo(4);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,pr1,my-label");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("pr1-foo", "pr1-bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,pr1,my-label");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-pr1-foo", "def-pr1-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:myapp,default,my-label");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(3).getName()).isEqualTo("vault:application,default,my-label");
assertThat(e.getPropertySources().get(3).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
private VaultEnvironmentRepository vaultEnvironmentRepository() {

View File

@@ -45,17 +45,17 @@ public class SpringVaultEnvironmentRepositoryTests {
private final VaultKeyValueOperations keyValueTemplate = mock(VaultKeyValueOperations.class);
@Test
public void testFindOneNoDefaultKey() {
public void findOneNoDefaultKey() {
defaultKeyTest("", 2);
}
@Test
public void testPathKey() {
public void findOneWithPathKey() {
defaultKeyTest("mypath", 2);
}
@Test
public void testPathKeyNotUsedWithVersionOne() {
public void findOneWithPathKeyNotUsedWithVersionOne() {
defaultKeyTest("mypath", 1);
}
@@ -77,12 +77,14 @@ public class SpringVaultEnvironmentRepositoryTests {
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void testBackendWithSlashes() {
public void findOneWithSlashesInBackend() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("application")).thenReturn(withVaultResponse("def-foo", "def-bar"));
@@ -94,29 +96,50 @@ public class SpringVaultEnvironmentRepositoryTests {
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void testFindOneDefaultKeySetAndDifferentToApplication() {
public void findOneWithDefaultKeySet() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("mydefaultkey")).thenReturn(withVaultResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setDefaultKey("mydefaultkey");
var e = springVaultEnvironmentRepository(properties).findOne("myapp", null, null);
var e = springVaultEnvironmentRepository(properties).findOne("myapp", null, "label");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:mydefaultkey");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void testFindOneDefaultKeySetAndDifferentToMultipleApplications() {
public void findOneWithEmptyDefaultKey() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("application")).thenReturn(withVaultResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setDefaultKey("");
var e = springVaultEnvironmentRepository(properties).findOne("myapp", null, "label");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(1);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
}
@Test
public void findOneWithDefaultKeyAndMultipleApplicationNames() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("myapp-foo", "myapp-bar"));
when(keyValueTemplate.get("yourapp")).thenReturn(withVaultResponse("yourapp-foo", "yourapp-bar"));
when(keyValueTemplate.get("mydefaultkey")).thenReturn(withVaultResponse("def-foo", "def-bar"));
@@ -124,18 +147,21 @@ public class SpringVaultEnvironmentRepositoryTests {
var properties = new VaultEnvironmentProperties();
properties.setDefaultKey("mydefaultkey");
var e = springVaultEnvironmentRepository(properties).findOne("myapp,yourapp", null, null);
var e = springVaultEnvironmentRepository(properties).findOne("myapp,yourapp", null, "lbl");
assertThat(e.getName()).isEqualTo("myapp,yourapp");
assertThat(e.getPropertySources()).hasSize(3);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:yourapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("yourapp-foo", "yourapp-bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("myapp-foo", "myapp-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:mydefaultkey");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void testFindOneDefaultKeySetAndEqualToApplication() {
public void findOneWithDefaultKeySetToApplicationName() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("application")).thenReturn(withVaultResponse("def-foo", "def-bar"));
@@ -147,11 +173,66 @@ public class SpringVaultEnvironmentRepositoryTests {
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(1);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
}
@Test
public void testVaultVersioning() {
public void findOneWithProfile() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("myapp,pr1")).thenReturn(withVaultResponse("foo-pr1", "bar-pr1"));
when(keyValueTemplate.get("application")).thenReturn(withVaultResponse("def-foo", "def-bar"));
when(keyValueTemplate.get("application,pr1")).thenReturn(withVaultResponse("def-pr1-foo", "def-pr1-bar"));
var properties = new VaultEnvironmentProperties();
var e = springVaultEnvironmentRepository(properties).findOne("myapp", "pr1", "lbl");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(4);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,pr1");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo-pr1", "bar-pr1"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,pr1");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-pr1-foo", "def-pr1-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(3).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(3).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithMultipleProfiles() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("myapp,pr1")).thenReturn(withVaultResponse("foo-pr1", "bar-pr1"));
when(keyValueTemplate.get("myapp,pr2")).thenReturn(withVaultResponse("foo-pr2", "bar-pr2"));
when(keyValueTemplate.get("application")).thenReturn(withVaultResponse("def-foo", "def-bar"));
when(keyValueTemplate.get("application,pr1")).thenReturn(withVaultResponse("def-pr1-foo", "def-pr1-bar"));
when(keyValueTemplate.get("application,pr2")).thenReturn(withVaultResponse("def-pr2-foo", "def-pr2-bar"));
var properties = new VaultEnvironmentProperties();
var e = springVaultEnvironmentRepository(properties).findOne("myapp", "pr1,pr2", "lbl");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(6);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,pr2");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo-pr2", "bar-pr2"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,pr2");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-pr2-foo", "def-pr2-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:myapp,pr1");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("foo-pr1", "bar-pr1"));
assertThat(e.getPropertySources().get(3).getName()).isEqualTo("vault:application,pr1");
assertThat(e.getPropertySources().get(3).getSource()).isEqualTo(Map.of("def-pr1-foo", "def-pr1-bar"));
assertThat(e.getPropertySources().get(4).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(4).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(5).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(5).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithVaultVersioning() {
when(keyValueTemplate.get("myapp")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("application")).thenReturn(withVaultResponse("def-foo", "def-bar"));
@@ -163,7 +244,94 @@ public class SpringVaultEnvironmentRepositoryTests {
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithDefaultLabelWhenLabelEnabled() {
when(keyValueTemplate.get("myapp,default,main")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("application,default,main")).thenReturn(withVaultResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
var e = springVaultEnvironmentRepository(properties).findOne("myapp", null, null);
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,default,main");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,default,main");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithProfileAndDefaultLabelWhenLabelEnabled() {
when(keyValueTemplate.get("myapp,default,main")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("myapp,pr1,main")).thenReturn(withVaultResponse("pr1-foo", "pr1-bar"));
when(keyValueTemplate.get("application,default,main")).thenReturn(withVaultResponse("def-foo", "def-bar"));
when(keyValueTemplate.get("application,pr1,main")).thenReturn(withVaultResponse("def-pr1-foo", "def-pr1-bar"));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
var e = springVaultEnvironmentRepository(properties).findOne("myapp", "pr1", null);
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(4);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,pr1,main");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("pr1-foo", "pr1-bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,pr1,main");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-pr1-foo", "def-pr1-bar"));
assertThat(e.getPropertySources().get(2).getName()).isEqualTo("vault:myapp,default,main");
assertThat(e.getPropertySources().get(2).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(3).getName()).isEqualTo("vault:application,default,main");
assertThat(e.getPropertySources().get(3).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithCustomDefaultLabelWhenLabelEnabled() {
when(keyValueTemplate.get("myapp,default,custom")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("application,default,custom")).thenReturn(withVaultResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
properties.setDefaultLabel("custom");
var e = springVaultEnvironmentRepository(properties).findOne("myapp", null, null);
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,default,custom");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,default,custom");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
@Test
public void findOneWithCustomLabelWhenLabelEnabled() {
when(keyValueTemplate.get("myapp,default,my-label")).thenReturn(withVaultResponse("foo", "bar"));
when(keyValueTemplate.get("application,default,my-label")).thenReturn(withVaultResponse("def-foo", "def-bar"));
var properties = new VaultEnvironmentProperties();
properties.setEnableLabel(true);
properties.setDefaultLabel("custom");
var e = springVaultEnvironmentRepository(properties).findOne("myapp", null, "my-label");
assertThat(e.getName()).isEqualTo("myapp");
assertThat(e.getPropertySources()).hasSize(2);
assertThat(e.getPropertySources().get(0).getName()).isEqualTo("vault:myapp,default,my-label");
assertThat(e.getPropertySources().get(0).getSource()).isEqualTo(Map.of("foo", "bar"));
assertThat(e.getPropertySources().get(1).getName()).isEqualTo("vault:application,default,my-label");
assertThat(e.getPropertySources().get(1).getSource()).isEqualTo(Map.of("def-foo", "def-bar"));
}
private SpringVaultEnvironmentRepository springVaultEnvironmentRepository(VaultEnvironmentProperties properties) {