diff --git a/docs/src/main/asciidoc/spring-cloud-vault.adoc b/docs/src/main/asciidoc/spring-cloud-vault.adoc index a929bedc..d6eb79bf 100644 --- a/docs/src/main/asciidoc/spring-cloud-vault.adoc +++ b/docs/src/main/asciidoc/spring-cloud-vault.adoc @@ -408,7 +408,7 @@ spring.cloud.vault: * `role` sets the name of the role against which the login is being attempted. * `azure-path` sets the path of the Azure mount to use -Azure MSI authentication fetches environmental details about the virtual machine +Azure MSI authentication fetches environmental details about the virtual machine (subscription Id, resource group, VM name) from the instance metadata service. See also: https://www.vaultproject.io/docs/auth/azure.html[Vault Documentation: Using the azure auth backend] @@ -549,9 +549,9 @@ and proves thereby its identity. This Vault backend treats GCP as a Trusted Thir IAM credentials can be obtained from either the runtime environment , specifically the https://cloud.google.com/docs/authentication/production[`GOOGLE_APPLICATION_CREDENTIALS`] -environment variable, the Google Compute metadata service, -or supplied externally as e.g. JSON or base64 encoded. -JSON is the preferred form as it carries the project id and +environment variable, the Google Compute metadata service, +or supplied externally as e.g. JSON or base64 encoded. +JSON is the preferred form as it carries the project id and service account identifier required for calling ``projects.serviceAccounts.signJwt``. .bootstrap.yml with required GCP-IAM Authentication properties @@ -1304,8 +1304,16 @@ after application shutdown. [source,yaml] ---- spring.cloud.vault: - config.lifecycle.enabled: true + config.lifecycle: + enabled: true + min-renewal: 10s + expiry-threshold: 1m + ---- ==== +* `enabled` controls whether leases associated with secrets are considered to be renewed and expired secrets are rotated. Enabled by default. +* `min-renewal` sets the duration that is at least required before renewing a lease. This setting prevents renewals from happening too often. +* `expiry-threshold` sets the expiry threshold. A lease is renewed the configured period of time before it expires. + See also: https://www.vaultproject.io/docs/concepts/lease.html[Vault Documentation: Lease, Renew, and Revoke] diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapPropertySourceConfiguration.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapPropertySourceConfiguration.java index 586bcc7e..cd592267 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapPropertySourceConfiguration.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapPropertySourceConfiguration.java @@ -43,6 +43,7 @@ import org.springframework.vault.core.lease.SecretLeaseContainer; * for Spring Vault's {@link PropertySourceLocator} support. * * @author Mark Paluch + * @author Grenville Wilson * @since 1.1 */ @Configuration @@ -87,7 +88,9 @@ public class VaultBootstrapPropertySourceConfiguration implements InitializingBe PropertySourceLocatorConfiguration configuration = getPropertySourceConfiguration( Arrays.asList(kvBackendProperties, genericBackendProperties)); - if (vaultProperties.getConfig().getLifecycle().isEnabled()) { + VaultProperties.Lifecycle lifecycle = vaultProperties.getConfig().getLifecycle(); + + if (lifecycle.isEnabled()) { // This is to destroy bootstrap resources // otherwise, the bootstrap context is not shut down cleanly @@ -96,14 +99,12 @@ public class VaultBootstrapPropertySourceConfiguration implements InitializingBe SecretLeaseContainer secretLeaseContainer = secretLeaseContainerObjectFactory .getObject(); - if (vaultProperties.getConfig().getLifecycle().getMinRenewal() != null) { - secretLeaseContainer.setMinRenewal( - vaultProperties.getConfig().getLifecycle().getMinRenewal()); + if (lifecycle.getMinRenewal() != null) { + secretLeaseContainer.setMinRenewal(lifecycle.getMinRenewal()); } - if (vaultProperties.getConfig().getLifecycle().getExpiryThreshold() != null) { - secretLeaseContainer.setMinRenewal( - vaultProperties.getConfig().getLifecycle().getExpiryThreshold()); + if (lifecycle.getExpiryThreshold() != null) { + secretLeaseContainer.setExpiryThreshold(lifecycle.getExpiryThreshold()); } secretLeaseContainer.start(); diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java index a3e72743..c846f4d5 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java @@ -35,6 +35,7 @@ import org.springframework.validation.annotation.Validated; * @author Mark Paluch * @author Kevin Holditch * @author Michal Budzyn + * @author Grenville Wilson */ @ConfigurationProperties("spring.cloud.vault") @Data @@ -484,12 +485,17 @@ public class VaultProperties implements EnvironmentAware { private boolean enabled = true; /** - * The amount of seconds that is at least required before renewing a lease. + * The time period that is at least required before renewing a lease. + * + * @since 2.2 */ private Duration minRenewal; /** - * The expiry threshold. {@link Lease} is renewed the given seconds before it expires. + * The expiry threshold. {@link Lease} is renewed the given {@link Duration} before it + * expires. + * + * @since 2.2 */ private Duration expiryThreshold; diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultBootstrapPropertySourceConfigurationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultBootstrapPropertySourceConfigurationTests.java new file mode 100644 index 00000000..c5bdab39 --- /dev/null +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultBootstrapPropertySourceConfigurationTests.java @@ -0,0 +1,79 @@ +/* + * Copyright 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 + * + * http://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.time.Duration; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.vault.core.VaultOperations; +import org.springframework.vault.core.lease.SecretLeaseContainer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Unit tests for {@link VaultBootstrapPropertySourceConfiguration}. + * + * @author Mark Paluch + */ +public class VaultBootstrapPropertySourceConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations + .of(VaultBootstrapPropertySourceConfiguration.class)); + + @Test + public void shouldConfigureExpiryTimeouts() { + + this.contextRunner.withUserConfiguration(MockConfiguration.class) + .withPropertyValues("spring.cloud.vault.generic.enabled=false", + "spring.cloud.vault.config.lifecycle.expiry-threshold=5m", + "spring.cloud.vault.config.lifecycle.min-renewal=6m") + .run(context -> { + + SecretLeaseContainer container = context + .getBean(SecretLeaseContainer.class); + assertThat(container.getExpiryThreshold()) + .isEqualTo(Duration.ofMinutes(5)); + assertThat(container.getMinRenewal()) + .isEqualTo(Duration.ofMinutes(6)); + }); + } + + @EnableConfigurationProperties(VaultProperties.class) + private static class MockConfiguration { + + @Bean + VaultOperations vaultOperations() { + return mock(VaultOperations.class); + } + + @Bean + VaultBootstrapConfiguration.TaskSchedulerWrapper taskSchedulerWrapper() { + return new VaultBootstrapConfiguration.TaskSchedulerWrapper( + mock(ThreadPoolTaskScheduler.class)); + } + + } + +}