Hello Spring Cloud Config Server Team,
We have a Spring Cloud Config Server via Spring Boot 2.4.2 + Ilford. The back end is Hashicorp Vault. We are using only the config server jar, no Spring-Vault-Config, no BetterCloud, etc...
Our current setup is:
spring.cloud.config.server.vault.backend=cubbyhole/somepath
spring.cloud.config.server.vault.host=our-vault-instance
spring.cloud.config.server.vault.port=443
spring.cloud.config.server.vault.scheme=https
spring.cloud.config.server.vault.authentication=cert
spring.cloud.config.server.vault.ssl.key-store=file://path/to/keystore.p12
spring.cloud.config.server.vault.ssl.key-store-password=the-password
spring.cloud.config.server.vault.ssl.cert-auth-path=cert
#spring.cloud.config.server.vault.token=we are NOT using token
And on client side, very straightforward
spring.config.import=optional:configserver:https://the-config-server-with-vault-back-end:8080
When the client starts, we see this in spring cloud config server debug logs:
o.s.web.servlet.DispatcherServlet : GET "/the-config-server-route/vault-path", parameters={}
.m.m.a.ExceptionHandlerExceptionResolver : Resolved [java.lang.IllegalArgumentException: Missing required header in HttpServletRequest: X-Config-Token]
o.s.web.servlet.DispatcherServlet : Completed 400 BAD_REQUEST
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
o.s.security.web.FilterChainProxy : Securing GET /error
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
o.s.security.web.FilterChainProxy : Secured GET /error
o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/vnd.spring-cloud.config-server.v2+json', given [application/vnd.spring-cloud.config-server.v2+json] and supported [application/json, application/*+json, application/json, application/*+json]
w.c.HttpSessionSecurityContextRepository : Did not store anonymous SecurityContext
o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 400
As you can see, it is still expecting a token as if we were not trying to connect via cert, but via token.
Te expected behavior would have been a connection to HTTP POST https://vault:443/v1/auth/cert/login in order to fetch the token first.
However, it is currently not sending any request to v1/auth/cert/login (Vault log monitored) and directly failing with the MISSING TOKEN.
Thank you
Comment From: ryanjbaxter
I assume this worked in Hoxton.SR9? Can you provide a sample?
Comment From: patpatpat123
Hello @ryanjbaxter ,
Correct, it was working fine before. Will try to extract an example. But maybe without the vault server itself, it might not help reproduce, since the server is just a ATConfigServer, and the client just point to the server, no code in the middle.
Will update this asap.
Comment From: patpatpat123
Hello @ryanjbaxter
Actually, the setup is pretty straightforward. Since I cannot provide an entire secure Vault with cert auth enabled, it is just 6 files in total (1 java file + 1 property file + 1 pom file), times two, client and server.
Server
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.marcosbarbero.wd</groupId>
<artifactId>config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>config-server</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<spring-cloud.version>2020.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
package com.marcosbarbero.wd.configserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
logging.level.ROOT=DEBUG
management.endpoints.web.exposure.include=info, health, env
server.port=8090
spring.profiles.active=vault
spring.application.name=configserver
spring.cloud.config.server.prefix=/config
spring.cloud.config.server.vault.backend=cubbyhole/test
spring.cloud.config.server.vault.host=the-vault-server-with-cert-auth
spring.cloud.config.server.vault.kvVersion=1
spring.cloud.config.server.vault.port=443
spring.cloud.config.server.vault.scheme=https
spring.cloud.config.server.vault.authentication=cert
spring.cloud.config.server.vault.ssl.key-store=file:/path/to/keystore/keystore-to-connect-to-vault.p12
spring.cloud.config.server.vault.ssl.key-store-password=
spring.cloud.config.server.vault.ssl.trust-store=file:/path/to/truststore/i-do-trust-vault.p12
spring.cloud.config.server.vault.ssl.trust-store-password=
#Note, this is using cert auth, not token
Comment From: patpatpat123
Client
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.marcosbarbero.wd</groupId>
<artifactId>config-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>config-client</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<spring-cloud.version>2020.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
package com.marcosbarbero.wd.configclient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Configuration
@RestController
@RefreshScope
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@GetMapping("/property")
public ResponseEntity<String> getProperty() {
return someService();
}
@Value("${client.pseudo.property}")
private String pseudoProperty;
public String getPseudoProperty() {
return pseudoProperty;
}
public ResponseEntity<String> someService() {
return ResponseEntity.ok(getPseudoProperty());
}
}
logging.level.ROOT=debug
spring.application.name=configclient
# spring.cloud.config.uri=http://localhost:8090/config not used anymore since 2.4
spring.config.import=optional:configserver:https://localhost:8090/config
spring.profiles.active=vault
Comment From: ryanjbaxter
Could you put the code in a git repo or attach it as a zip?
Comment From: patpatpat123
Uploading spring-cloud-configserver-vault.zip…
Comment From: patpatpat123
And running it will yield the
.m.m.a.ExceptionHandlerExceptionResolver : Resolved [java.lang.IllegalArgumentException: Missing required header in HttpServletRequest: X-Config-Token]
o.s.web.servlet.DispatcherServlet : Completed 400 BAD_REQUEST
Again, apologies I cannot provide a secure vault with certificates configured, alongside the client certificates.