From 9ef8deea0427e03cf5ed8932462c213d3572fbe7 Mon Sep 17 00:00:00 2001 From: Vlad Rosu Date: Fri, 6 Mar 2020 10:20:21 +0200 Subject: [PATCH 1/6] Fix for namespace not being propagated on Auth schemes (except Token) --- .../vault/SpringVaultClientConfiguration.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java index 635239e4..fce2524e 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java @@ -96,9 +96,7 @@ public class SpringVaultClientConfiguration extends AbstractVaultConfiguration { endpointProvider, requestFactory); if (vaultProperties.getNamespace() != null) { - restTemplateBuilder.customizers( - restTemplate -> restTemplate.getInterceptors().add(VaultClients - .createNamespaceInterceptor(vaultProperties.getNamespace()))); + restTemplateBuilder.customizers(this::applyNamespaceInterceptor); } return restTemplateBuilder; @@ -125,6 +123,13 @@ public class SpringVaultClientConfiguration extends AbstractVaultConfiguration { return new SslConfiguration(keyStoreConfiguration, trustStoreConfiguration); } + @Override + public RestOperations restOperations() { + RestTemplate restOperations = (RestTemplate) super.restOperations(); + applyNamespaceInterceptor(restOperations); + return restOperations; + } + private SslConfiguration.KeyStoreConfiguration getKeyStoreConfiguration( Resource resourceProperty, String passwordProperty) { @@ -140,6 +145,15 @@ public class SpringVaultClientConfiguration extends AbstractVaultConfiguration { return SslConfiguration.KeyStoreConfiguration.of(resourceProperty); } + private RestOperations applyNamespaceInterceptor(RestTemplate restTemplate) { + if (vaultProperties.getNamespace() != null) { + restTemplate.getInterceptors().add(VaultClients + .createNamespaceInterceptor(vaultProperties.getNamespace())); + } + + return restTemplate; + } + /** * @return a new {@link ClientAuthentication}. */ From 39e09d59b221eb326ab2bd9e4ad119efab1c37c1 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 18 Mar 2020 17:52:55 -0400 Subject: [PATCH 2/6] Updates to build 2.2.4.BUILD-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 55cf4003..9c0c2dbf 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.springframework.cloud spring-cloud-build - 2.2.3.RELEASE + 2.2.4.BUILD-SNAPSHOT From 904ae1e3e69d083587f0165e1aed50fd59cfd7b8 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Thu, 19 Mar 2020 10:53:15 -0400 Subject: [PATCH 3/6] Updates to build 2.3.0.BUILD-SNAPSHOT --- pom.xml | 2 +- spring-cloud-config-dependencies/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9c0c2dbf..4c316837 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.springframework.cloud spring-cloud-build - 2.2.4.BUILD-SNAPSHOT + 2.3.0.BUILD-SNAPSHOT diff --git a/spring-cloud-config-dependencies/pom.xml b/spring-cloud-config-dependencies/pom.xml index dee3f717..26050ed6 100644 --- a/spring-cloud-config-dependencies/pom.xml +++ b/spring-cloud-config-dependencies/pom.xml @@ -6,7 +6,7 @@ spring-cloud-dependencies-parent org.springframework.cloud - 2.2.4.BUILD-SNAPSHOT + 2.3.0.BUILD-SNAPSHOT spring-cloud-config-dependencies From 959f492ddf77cbfe84dc4d3f6633ebf4118019d7 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Mon, 30 Mar 2020 14:13:49 -0500 Subject: [PATCH 4/6] Polish and add tests. Polish the code and add tests for SpringVaultClientConfiguration when a namespace is configured. Fixes gh-1589 --- .../vault/SpringVaultClientConfiguration.java | 12 +++-- .../SpringVaultClientConfigurationTests.java | 44 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java index da7f8c34..5009583d 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java @@ -130,11 +130,17 @@ public class SpringVaultClientConfiguration extends AbstractVaultConfiguration return new SslConfiguration(keyStoreConfiguration, trustStoreConfiguration); } + /** + * This method is a work-around for the Spring Vault issue documented in + * https://github.com/spring-projects/spring-vault/issues/546. The method should be + * removed when Spring Cloud Config is upgraded to the version of Spring Vault that + * includes the fix for the issue. + * @return the {@link RestOperations} to be used for Vault access + */ @Override public RestOperations restOperations() { - RestTemplate restOperations = (RestTemplate) super.restOperations(); - applyNamespaceInterceptor(restOperations); - return restOperations; + return restTemplateBuilder(vaultEndpointProvider(), + clientHttpRequestFactoryWrapper().getClientHttpRequestFactory()).build(); } private SslConfiguration.KeyStoreConfiguration getKeyStoreConfiguration( diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java index 2641a22c..2774ae58 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java @@ -25,6 +25,7 @@ import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.context.annotation.UserConfigurations; @@ -45,6 +46,10 @@ import org.springframework.cloud.config.server.environment.vault.authentication. import org.springframework.cloud.config.server.environment.vault.authentication.PcfClientAuthenticationProvider; import org.springframework.cloud.config.server.environment.vault.authentication.TokenClientAuthenticationProvider; import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.mock.http.client.MockClientHttpRequest; import org.springframework.util.ClassUtils; import org.springframework.vault.authentication.AppRoleAuthentication; import org.springframework.vault.authentication.AwsEc2Authentication; @@ -58,8 +63,11 @@ import org.springframework.vault.authentication.GcpIamAuthentication; import org.springframework.vault.authentication.KubernetesAuthentication; import org.springframework.vault.authentication.PcfAuthentication; import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.client.VaultHttpHeaders; import org.springframework.vault.support.SslConfiguration; import org.springframework.vault.support.SslConfiguration.KeyStoreConfiguration; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.APPROLE; @@ -280,6 +288,42 @@ class SpringVaultClientConfigurationTests { .isEqualTo("password"); } + @Test + public void namespaceHeaderNotAddedWhenNamespaceNotConfigured() throws IOException { + VaultEnvironmentProperties properties = new VaultEnvironmentProperties(); + + SpringVaultClientConfiguration configuration = getConfiguration(properties); + HttpRequest request = invokeInterceptors(configuration.restOperations()); + assertThat(request.getHeaders().getFirst(VaultHttpHeaders.VAULT_NAMESPACE)) + .isNull(); + } + + @Test + public void namespaceInterceptorAddedWhenNamespaceConfigured() throws IOException { + VaultEnvironmentProperties properties = new VaultEnvironmentProperties(); + properties.setNamespace("test-namespace"); + + SpringVaultClientConfiguration configuration = getConfiguration(properties); + HttpRequest request = invokeInterceptors(configuration.restOperations()); + assertThat(request.getHeaders().getFirst(VaultHttpHeaders.VAULT_NAMESPACE)) + .isEqualTo("test-namespace"); + } + + private HttpRequest invokeInterceptors(RestOperations restOperations) + throws IOException { + assertThat(restOperations).isInstanceOf(RestTemplate.class); + RestTemplate restTemplate = (RestTemplate) restOperations; + + MockClientHttpRequest request = new MockClientHttpRequest(); + ClientHttpRequestExecution execution = Mockito + .mock(ClientHttpRequestExecution.class); + byte[] body = new byte[] {}; + for (ClientHttpRequestInterceptor interceptor : restTemplate.getInterceptors()) { + interceptor.intercept(request, body, execution); + } + return request; + } + private void assertClientAuthenticationOfType(VaultEnvironmentProperties properties, Class type) { ClientAuthentication clientAuthentication = getConfiguration(properties) From fa39c01398f24a33c739c447cc1e336f38558456 Mon Sep 17 00:00:00 2001 From: "justin.bertrand" Date: Wed, 11 Mar 2020 09:43:04 -0400 Subject: [PATCH 5/6] Expansion of Vault Azure MSI Configuration properties and bug fix. fixes gh-1573 --- .../VaultEnvironmentProperties.java | 26 +++++++++++++++++++ .../AzureMsiClientAuthenticationProvider.java | 16 +++++++++++- .../SpringVaultClientConfigurationTests.java | 12 +++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentProperties.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentProperties.java index f561beb2..f82b58df 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentProperties.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/VaultEnvironmentProperties.java @@ -525,10 +525,28 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp */ private String role = ""; + /** + * URI to the Azure MSI Identity Service. + */ + private String identityTokenService = ""; + + /** + * URI to the Azure MSI Metadata Service. + */ + private String metadataService = ""; + public String getAzurePath() { return this.azurePath; } + public String getIdentityTokenService() { + return identityTokenService; + } + + public String getMetadataService() { + return metadataService; + } + public String getRole() { return this.role; } @@ -537,6 +555,14 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp this.azurePath = azurePath; } + public void setIdentityTokenService(String identityTokenService) { + this.identityTokenService = identityTokenService; + } + + public void setMetadataService(String metadataService) { + this.metadataService = metadataService; + } + public void setRole(String role) { this.role = role; } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/authentication/AzureMsiClientAuthenticationProvider.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/authentication/AzureMsiClientAuthenticationProvider.java index 9da54df4..901aaa1f 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/authentication/AzureMsiClientAuthenticationProvider.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/authentication/AzureMsiClientAuthenticationProvider.java @@ -16,6 +16,8 @@ package org.springframework.cloud.config.server.environment.vault.authentication; +import java.net.URI; + import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties; import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod; import org.springframework.cloud.config.server.environment.vault.SpringVaultClientAuthenticationProvider; @@ -44,10 +46,22 @@ public class AzureMsiClientAuthenticationProvider AuthenticationMethod.AZURE_MSI)); AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder() - .role(azureMsi.getRole()).build(); + .role(azureMsi.getRole()).path(azureMsi.getAzurePath()) + .instanceMetadataUri(getUri(azureMsi.getMetadataService(), + AzureMsiAuthenticationOptions.DEFAULT_INSTANCE_METADATA_SERVICE_URI)) + .identityTokenServiceUri(getUri(azureMsi.getIdentityTokenService(), + AzureMsiAuthenticationOptions.DEFAULT_IDENTITY_TOKEN_SERVICE_URI)) + .build(); return new AzureMsiAuthentication(options, vaultRestOperations, externalRestOperations); } + private URI getUri(String uriString, URI defaultUri) { + if (uriString == null || uriString.isEmpty()) { + return defaultUri; + } + return URI.create(uriString); + } + } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java index 2774ae58..ad10a94c 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java @@ -50,11 +50,13 @@ import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.ClassUtils; import org.springframework.vault.authentication.AppRoleAuthentication; import org.springframework.vault.authentication.AwsEc2Authentication; import org.springframework.vault.authentication.AwsIamAuthentication; import org.springframework.vault.authentication.AzureMsiAuthentication; +import org.springframework.vault.authentication.AzureMsiAuthenticationOptions; import org.springframework.vault.authentication.ClientAuthentication; import org.springframework.vault.authentication.ClientCertificateAuthentication; import org.springframework.vault.authentication.CubbyholeAuthentication; @@ -81,6 +83,8 @@ import static org.springframework.cloud.config.server.environment.VaultEnvironme import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.KUBERNETES; import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.PCF; import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.TOKEN; +import static org.springframework.vault.authentication.AzureMsiAuthenticationOptions.DEFAULT_IDENTITY_TOKEN_SERVICE_URI; +import static org.springframework.vault.authentication.AzureMsiAuthenticationOptions.DEFAULT_INSTANCE_METADATA_SERVICE_URI; class SpringVaultClientConfigurationTests { @@ -145,6 +149,14 @@ class SpringVaultClientConfigurationTests { properties.getAzureMsi().setAzurePath("azure-msi"); assertClientAuthenticationOfType(properties, AzureMsiAuthentication.class); + + AzureMsiAuthentication clientAuthentication = (AzureMsiAuthentication) getConfiguration(properties) + .clientAuthentication(); + AzureMsiAuthenticationOptions options = (AzureMsiAuthenticationOptions) ReflectionTestUtils + .getField(clientAuthentication, "options"); + + assertThat(options.getIdentityTokenServiceUri()).isEqualTo(DEFAULT_IDENTITY_TOKEN_SERVICE_URI); + assertThat(options.getInstanceMetadataServiceUri()).isEqualTo(DEFAULT_INSTANCE_METADATA_SERVICE_URI); } @Test From 480baf20a18b6e82c7a5573620cb950c7fec9741 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 8 Apr 2020 17:13:12 -0400 Subject: [PATCH 6/6] formatting --- .../vault/SpringVaultClientConfigurationTests.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java index ad10a94c..7d3f6b61 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java @@ -150,13 +150,15 @@ class SpringVaultClientConfigurationTests { assertClientAuthenticationOfType(properties, AzureMsiAuthentication.class); - AzureMsiAuthentication clientAuthentication = (AzureMsiAuthentication) getConfiguration(properties) - .clientAuthentication(); + AzureMsiAuthentication clientAuthentication = (AzureMsiAuthentication) getConfiguration( + properties).clientAuthentication(); AzureMsiAuthenticationOptions options = (AzureMsiAuthenticationOptions) ReflectionTestUtils - .getField(clientAuthentication, "options"); + .getField(clientAuthentication, "options"); - assertThat(options.getIdentityTokenServiceUri()).isEqualTo(DEFAULT_IDENTITY_TOKEN_SERVICE_URI); - assertThat(options.getInstanceMetadataServiceUri()).isEqualTo(DEFAULT_INSTANCE_METADATA_SERVICE_URI); + assertThat(options.getIdentityTokenServiceUri()) + .isEqualTo(DEFAULT_IDENTITY_TOKEN_SERVICE_URI); + assertThat(options.getInstanceMetadataServiceUri()) + .isEqualTo(DEFAULT_INSTANCE_METADATA_SERVICE_URI); } @Test