Fix versioned key-value access with disabled lifecycle support

Versioned key-value secrets are now loaded properly when lifecycle support is disabled.

We're using our own mechanism to read secrets instead of using Spring Vault's property source so we need to inspect whether the mount is a key-value v1 or v2 one to load its value properly.

Closes gh-372.
This commit is contained in:
Mark Paluch
2019-12-02 09:54:53 +01:00
parent c87ff55123
commit 30378c8761
3 changed files with 119 additions and 3 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2016-2019 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.
@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.vault.VaultException;
import org.springframework.vault.core.VaultOperations;
import org.springframework.vault.core.util.KeyValueDelegate;
import org.springframework.vault.core.util.PropertyTransformer;
import org.springframework.vault.support.JsonMapFlattener;
import org.springframework.vault.support.VaultResponse;
@@ -42,6 +43,8 @@ public class VaultConfigTemplate implements VaultConfigOperations {
private final VaultProperties properties;
private final KeyValueDelegate keyValueDelegate;
/**
* Create a new {@link VaultConfigTemplate} given {@link VaultOperations}.
* @param vaultOperations must not be {@literal null}.
@@ -55,6 +58,7 @@ public class VaultConfigTemplate implements VaultConfigOperations {
this.vaultOperations = vaultOperations;
this.properties = properties;
this.keyValueDelegate = new KeyValueDelegate(vaultOperations);
}
@Override
@@ -66,8 +70,17 @@ public class VaultConfigTemplate implements VaultConfigOperations {
secretBackendMetadata.getPath()));
try {
VaultResponse vaultResponse = this.vaultOperations
.read(secretBackendMetadata.getPath());
VaultResponse vaultResponse;
if (this.keyValueDelegate.isVersioned(secretBackendMetadata.getPath())) {
vaultResponse = this.keyValueDelegate
.getSecret(secretBackendMetadata.getPath());
}
else {
vaultResponse = this.vaultOperations
.read(secretBackendMetadata.getPath());
}
if (vaultResponse == null) {

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2018-2019 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.Before;
import org.junit.Test;
import org.springframework.cloud.vault.util.IntegrationTestSupport;
import org.springframework.cloud.vault.util.Settings;
import org.springframework.cloud.vault.util.Version;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;
/**
* Integration tests for {@link VaultConfigTemplate}.
*
* @author Mark Paluch
*/
public class VaultConfigTemplateIntegrationTests extends IntegrationTestSupport {
@Before
public void before() {
prepare().getVaultOperations().write("secret/myapp",
Collections.singletonMap("key", "value"));
}
@Test
public void shouldReadValue() {
VaultProperties vaultProperties = Settings.createVaultProperties();
VaultConfigTemplate template = new VaultConfigTemplate(
prepare().getVaultOperations(), vaultProperties);
Secrets secrets = template
.read(GenericSecretBackendMetadata.create("secret", "myapp"));
assertThat(secrets.getData()).containsEntry("key", "value");
}
@Test
public void shouldReadVersionedValue() {
assumeTrue(this.vaultRule.prepare().getVersion()
.isGreaterThanOrEqualTo(Version.parse("0.10.0")));
this.vaultRule.prepare().getVaultOperations().write("versioned/data/testVaultApp",
Collections.singletonMap("data",
Collections.singletonMap("key", "value")));
VaultProperties vaultProperties = Settings.createVaultProperties();
VaultConfigTemplate template = new VaultConfigTemplate(
prepare().getVaultOperations(), vaultProperties);
Secrets secrets = template
.read(GenericSecretBackendMetadata.create("versioned", "testVaultApp"));
assertThat(secrets.getData()).containsEntry("key", "value");
}
}

View File

@@ -23,8 +23,10 @@ import org.junit.Test;
import org.springframework.cloud.vault.util.IntegrationTestSupport;
import org.springframework.cloud.vault.util.Settings;
import org.springframework.cloud.vault.util.Version;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;
/**
* Integration tests for {@link VaultPropertySource}.
@@ -54,4 +56,26 @@ public class VaultPropertySourceIntegrationTests extends IntegrationTestSupport
assertThat(propertySource.getProperty("key")).isEqualTo("value");
}
@Test
public void shouldReadVersionedValue() {
assumeTrue(this.vaultRule.prepare().getVersion()
.isGreaterThanOrEqualTo(Version.parse("0.10.0")));
this.vaultRule.prepare().getVaultOperations().write("versioned/data/testVaultApp",
Collections.singletonMap("data",
Collections.singletonMap("key", "value")));
VaultProperties vaultProperties = Settings.createVaultProperties();
VaultPropertySource propertySource = new VaultPropertySource(
new VaultConfigTemplate(prepare().getVaultOperations(), vaultProperties),
false, GenericSecretBackendMetadata.create("versioned", "testVaultApp"));
propertySource.init();
assertThat(propertySource.getPropertyNames()).contains("key");
assertThat(propertySource.getProperty("key")).isEqualTo("value");
}
}