Introduce profile override for Key Value backend.
We now provide an override spring.cloud.vault.kv.profiles=… to specify application profiles that should be used for Vault access instead of Environment.getActiveProfiles(). Closes gh-385.
This commit is contained in:
@@ -694,6 +694,11 @@ The application name is determined by the properties:
|
||||
* `spring.cloud.vault.application-name`
|
||||
* `spring.application.name`
|
||||
|
||||
The profiles are determined by the properties:
|
||||
|
||||
* `spring.cloud.vault.kv.profiles`
|
||||
* `spring.profiles.active`
|
||||
|
||||
Secrets can be obtained from other contexts within the key-value backend by adding their paths to the application name, separated by commas.
|
||||
For example, given the application name `usefulapp,mysql1,projectx/aws`, each of these folders will be used:
|
||||
|
||||
@@ -706,7 +711,7 @@ No active profiles will skip accessing contexts with a profile name.
|
||||
|
||||
Properties are exposed like they are stored (i.e. without additional prefixes).
|
||||
|
||||
NOTE: Spring Cloud Vault adds the `data/` context between the mount path and the actual context path.
|
||||
NOTE: Spring Cloud Vault adds the `data/` context between the mount path and the actual context path depending on whether the mount uses the versioned key-value backend.
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
@@ -718,6 +723,7 @@ spring.cloud.vault:
|
||||
profile-separator: '/'
|
||||
default-context: application
|
||||
application-name: my-app
|
||||
profiles: local, cloud
|
||||
----
|
||||
====
|
||||
|
||||
@@ -725,6 +731,7 @@ spring.cloud.vault:
|
||||
* `backend` sets the path of the secret mount to use
|
||||
* `default-context` sets the context name used by all applications
|
||||
* `application-name` overrides the application name for use in the key-value backend
|
||||
* `profiles` overrides the active profiles for use in the key-value backend
|
||||
* `profile-separator` separates the profile name from the context in property sources with profiles
|
||||
|
||||
NOTE: The key-value secret backend can be operated in versioned (v2) and non-versioned (v1) modes.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -141,9 +140,8 @@ public class VaultBootstrapPropertySourceConfiguration implements InitializingBe
|
||||
continue;
|
||||
}
|
||||
|
||||
List<String> contexts = KeyValueSecretBackendMetadata.buildContexts(
|
||||
keyValueBackend, Arrays.asList(this.applicationContext
|
||||
.getEnvironment().getActiveProfiles()));
|
||||
List<String> contexts = KeyValueSecretBackendMetadata
|
||||
.buildContexts(keyValueBackend, keyValueBackend.getProfiles());
|
||||
|
||||
for (String context : contexts) {
|
||||
secretBackendConfigurer.add(KeyValueSecretBackendMetadata
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@@ -63,6 +68,12 @@ public class VaultKeyValueBackendProperties
|
||||
*/
|
||||
private String applicationName = "application";
|
||||
|
||||
/**
|
||||
* List of active profiles.
|
||||
* @since 3.0
|
||||
*/
|
||||
private List<String> profiles;
|
||||
|
||||
/**
|
||||
* Key-Value backend version. Currently supported versions are:
|
||||
* <ul>
|
||||
@@ -91,6 +102,10 @@ public class VaultKeyValueBackendProperties
|
||||
this.applicationName = springAppName;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.profiles == null) {
|
||||
this.profiles = Arrays.asList(environment.getActiveProfiles());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
@@ -113,6 +128,14 @@ public class VaultKeyValueBackendProperties
|
||||
return this.applicationName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getProfiles() {
|
||||
if (this.profiles == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(new ArrayList<>(this.profiles));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@DeprecatedConfigurationProperty(
|
||||
reason = "Backend version no longer required. The kv version is determined during secret retrieval")
|
||||
@@ -140,6 +163,10 @@ public class VaultKeyValueBackendProperties
|
||||
this.applicationName = applicationName;
|
||||
}
|
||||
|
||||
public void setProfiles(List<String> profiles) {
|
||||
this.profiles = profiles;
|
||||
}
|
||||
|
||||
public void setBackendVersion(int backendVersion) {
|
||||
this.backendVersion = backendVersion;
|
||||
}
|
||||
@@ -153,6 +180,7 @@ public class VaultKeyValueBackendProperties
|
||||
sb.append(", defaultContext='").append(this.defaultContext).append('\'');
|
||||
sb.append(", profileSeparator='").append(this.profileSeparator).append('\'');
|
||||
sb.append(", applicationName='").append(this.applicationName).append('\'');
|
||||
sb.append(", profiles='").append(this.profiles).append('\'');
|
||||
sb.append(", backendVersion=").append(this.backendVersion);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface declaring Key-Value configuration properties.
|
||||
*
|
||||
@@ -50,4 +52,10 @@ public interface VaultKeyValueBackendPropertiesSupport {
|
||||
*/
|
||||
String getApplicationName();
|
||||
|
||||
/**
|
||||
* @return the application profiles to use.
|
||||
* @since 3.0
|
||||
*/
|
||||
List<String> getProfiles();
|
||||
|
||||
}
|
||||
|
||||
@@ -178,22 +178,15 @@ public abstract class VaultPropertySourceLocatorSupport implements PropertySourc
|
||||
SecretBackendMetadata accessor);
|
||||
|
||||
private static class KeyValuePropertySourceLocatorConfiguration
|
||||
implements EnvironmentAware, PropertySourceLocatorConfiguration {
|
||||
implements PropertySourceLocatorConfiguration {
|
||||
|
||||
private final VaultKeyValueBackendPropertiesSupport keyValueBackendProperties;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
KeyValuePropertySourceLocatorConfiguration(
|
||||
VaultKeyValueBackendPropertiesSupport keyValueBackendProperties) {
|
||||
this.keyValueBackendProperties = keyValueBackendProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SecretBackendMetadata> getSecretBackends() {
|
||||
|
||||
@@ -201,7 +194,7 @@ public abstract class VaultPropertySourceLocatorSupport implements PropertySourc
|
||||
|
||||
List<String> contexts = KeyValueSecretBackendMetadata.buildContexts(
|
||||
this.keyValueBackendProperties,
|
||||
Arrays.asList(this.environment.getActiveProfiles()));
|
||||
this.keyValueBackendProperties.getProfiles());
|
||||
|
||||
List<SecretBackendMetadata> result = new ArrayList<>(contexts.size());
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.springframework.vault.core.lease.domain.RequestedSecret;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link LeasingVaultPropertySourceLocator}.
|
||||
@@ -48,12 +47,14 @@ public class LeasingVaultPropertySourceLocatorUnitTests {
|
||||
@Mock
|
||||
private SecretLeaseContainer secretLeaseContainer;
|
||||
|
||||
private VaultKeyValueBackendProperties properties = new VaultKeyValueBackendProperties();
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
|
||||
this.propertySourceLocator = new LeasingVaultPropertySourceLocator(
|
||||
new VaultProperties(), VaultPropertySourceLocatorSupport
|
||||
.createConfiguration(new VaultKeyValueBackendProperties()),
|
||||
new VaultProperties(),
|
||||
VaultPropertySourceLocatorSupport.createConfiguration(this.properties),
|
||||
this.secretLeaseContainer);
|
||||
}
|
||||
|
||||
@@ -74,8 +75,6 @@ public class LeasingVaultPropertySourceLocatorUnitTests {
|
||||
@Test
|
||||
public void shouldLocatePropertySources() {
|
||||
|
||||
when(this.configurableEnvironment.getActiveProfiles()).thenReturn(new String[0]);
|
||||
|
||||
PropertySource<?> propertySource = this.propertySourceLocator
|
||||
.locate(this.configurableEnvironment);
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.cloud.vault.util.VaultRule;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration test incorporating loading secrets using
|
||||
* {@code spring.cloud.vault.kv.profiles}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(
|
||||
classes = VaultPropertySourceLocatorProfilesIntegrationTests.TestApplication.class,
|
||||
properties = { "spring.application.name=my-profiles-app",
|
||||
"spring.cloud.vault.kv.profiles=hello, world",
|
||||
"spring.cloud.vault.kv.default-context=" })
|
||||
@ActiveProfiles({ "other" })
|
||||
public class VaultPropertySourceLocatorProfilesIntegrationTests
|
||||
extends IntegrationTestSupport {
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
|
||||
VaultRule vaultRule = new VaultRule();
|
||||
vaultRule.before();
|
||||
|
||||
vaultRule.prepare().getVaultOperations().write("secret/my-profiles-app/hello",
|
||||
Collections.singletonMap("vault.hello", "true"));
|
||||
|
||||
vaultRule.prepare().getVaultOperations().write("secret/my-profiles-app/world",
|
||||
Collections.singletonMap("vault.world", "true"));
|
||||
|
||||
vaultRule.prepare().getVaultOperations().write("secret/my-profiles-app/other",
|
||||
Collections.singletonMap("vault.other", "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldContainValuesFromKvProfiles() {
|
||||
assertThat(this.environment.getRequiredProperty("vault.hello")).isEqualTo("true");
|
||||
assertThat(this.environment.getRequiredProperty("vault.world")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotContainVaulesFromSpringProfiles() {
|
||||
assertThat(this.environment.getProperty("vault.other")).isNull();
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
public static class TestApplication {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -28,7 +30,6 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link VaultPropertySourceLocator}.
|
||||
@@ -47,11 +48,13 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
@Mock
|
||||
private ConfigurableEnvironment configurableEnvironment;
|
||||
|
||||
private VaultKeyValueBackendProperties properties = new VaultKeyValueBackendProperties();
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.propertySourceLocator = new VaultPropertySourceLocator(this.operations,
|
||||
new VaultProperties(), VaultPropertySourceLocatorSupport
|
||||
.createConfiguration(new VaultKeyValueBackendProperties()));
|
||||
new VaultProperties(),
|
||||
VaultPropertySourceLocatorSupport.createConfiguration(this.properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -70,8 +73,6 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
@Test
|
||||
public void shouldLocateOnePropertySourceWithEmptyProfiles() {
|
||||
|
||||
when(this.configurableEnvironment.getActiveProfiles()).thenReturn(new String[0]);
|
||||
|
||||
PropertySource<?> propertySource = this.propertySourceLocator
|
||||
.locate(this.configurableEnvironment);
|
||||
|
||||
@@ -84,8 +85,7 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
@Test
|
||||
public void shouldLocatePropertySourcesForActiveProfilesInDefaultContext() {
|
||||
|
||||
when(this.configurableEnvironment.getActiveProfiles())
|
||||
.thenReturn(new String[] { "vermillion", "periwinkle" });
|
||||
this.properties.setProfiles(Arrays.asList("vermillion", "periwinkle"));
|
||||
|
||||
PropertySource<?> propertySource = this.propertySourceLocator
|
||||
.locate(this.configurableEnvironment);
|
||||
@@ -102,14 +102,12 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
|
||||
VaultKeyValueBackendProperties backendProperties = new VaultKeyValueBackendProperties();
|
||||
backendProperties.setApplicationName("wintermute");
|
||||
backendProperties.setProfiles(Arrays.asList("vermillion", "periwinkle"));
|
||||
|
||||
this.propertySourceLocator = new VaultPropertySourceLocator(this.operations,
|
||||
new VaultProperties(),
|
||||
VaultPropertySourceLocatorSupport.createConfiguration(backendProperties));
|
||||
|
||||
when(this.configurableEnvironment.getActiveProfiles())
|
||||
.thenReturn(new String[] { "vermillion", "periwinkle" });
|
||||
|
||||
PropertySource<?> propertySource = this.propertySourceLocator
|
||||
.locate(this.configurableEnvironment);
|
||||
|
||||
@@ -126,14 +124,12 @@ public class VaultPropertySourceLocatorUnitTests {
|
||||
|
||||
VaultKeyValueBackendProperties backendProperties = new VaultKeyValueBackendProperties();
|
||||
backendProperties.setApplicationName("wintermute,straylight,icebreaker/armitage");
|
||||
backendProperties.setProfiles(Arrays.asList("vermillion", "periwinkle"));
|
||||
|
||||
this.propertySourceLocator = new VaultPropertySourceLocator(this.operations,
|
||||
new VaultProperties(),
|
||||
VaultPropertySourceLocatorSupport.createConfiguration(backendProperties));
|
||||
|
||||
when(this.configurableEnvironment.getActiveProfiles())
|
||||
.thenReturn(new String[] { "vermillion", "periwinkle" });
|
||||
|
||||
PropertySource<?> propertySource = this.propertySourceLocator
|
||||
.locate(this.configurableEnvironment);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user