spring-native
spring-native copied to clipboard
Add Spring Cloud Config Vault support
Hello everyone, I'm trying to run a POC for spring native project using:
- graalVM (21.2.0.r11-grl)
- spring boot (2.6.1)
- spring cloud config (2021.0.0)
- spring native (0.11.0) My app just expose two endpoint using restController , and retrieve config from Vault (using token authentication method). my pom.xml :
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.smarthome</groupId>
<artifactId>enki-poc-v2-native</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>enki-poc-v2-native</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<repackage.classifier/>
<spring-cloud.version>2021.0.0</spring-cloud.version>
<spring-native.version>0.11.0</spring-native.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</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>
<configuration>
<classifier>${repackage.classifier}</classifier>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>${spring-native.version}</version>
<executions>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>native</id>
<properties>
<repackage.classifier>exec</repackage.classifier>
<native-buildtools.version>0.9.8</native-buildtools.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>${native-buildtools.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>test-native</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
<execution>
<id>build-native</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
my application.yml
spring:
profiles:
active: ${APP_PROFILES}
and my application-local.yml looks like :
spring:
application.name: enki-poc-v2-native
cloud.vault:
application-name: ${spring.application.name}
namespace: frlm/enki-foundations
token: ${VAULT_TOKEN}
uri: https://vault.factory.adeo.cloud
authentication: token
config.lifecycle.enabled: true
fail-fast: true
config:
import: vault://secret/enki-poc-v2/local
cloud:
compatibility-verifier:
enabled: false
# management api
management.endpoint.health.enabled: true
management.endpoints.web.base-path:
the build-native ( mvn spring-boot:build-image) run successfully , and I'm able to see the docker image created in my local repo.
When I try to run docker image using the command: docker run --rm -p 8080:8080 -e VAULT_TOKEN=s.uaJCGGWHG2Wpv3XptXG1HMba.4iZOA -e APP_PROFILES=local enki-poc-v2-native:0.0.1-SNAPSHOT
first I was having the issue :
Native reflection configuration for org.springframework.cloud.vault.config.VaultConfigDataLocationResolver is missing.
and I fix it by adding a TypeHint:
@TypeHint(typeNames = "org.springframework.cloud.vault.config.VaultConfigDataLocationResolver")
Now I'm facing another issue , with the error:
➜ enki-poc-v2-native git:(main) ✗ docker run --rm -p 8080:8080 -e VAULT_TOKEN=s.uaJCGGWHG2Wpv3XptXG1HMba.4iZOA -e APP_PROFILES=local enki-poc-v2-native:0.0.1-SNAPSHOT
15:25:51.372 [main] INFO org.springframework.boot.SpringApplication - AOT mode enabled
15:25:51.416 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalArgumentException: Unable to instantiate org.springframework.boot.context.config.ConfigDataLoader [org.springframework.cloud.vault.config.VaultConfigDataLoader]
at org.springframework.boot.util.Instantiator.instantiate(Instantiator.java:131)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.springframework.boot.util.Instantiator.instantiate(Instantiator.java:118)
at org.springframework.boot.util.Instantiator.instantiate(Instantiator.java:103)
at org.springframework.boot.context.config.ConfigDataLoaders.<init>(ConfigDataLoaders.java:80)
at org.springframework.boot.context.config.ConfigDataLoaders.<init>(ConfigDataLoaders.java:58)
at org.springframework.boot.context.config.ConfigDataEnvironment.<init>(ConfigDataEnvironment.java:152)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.getConfigDataEnvironment(ConfigDataEnvironmentPostProcessor.java:114)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:85)
at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:66)
at java.util.ArrayList.forEach(ArrayList.java:1541)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:65)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:338)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:296)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290)
at com.smarthome.enkipocv2native.EnkiPocV2NativeApplication.main(EnkiPocV2NativeApplication.java:13)
Caused by: java.lang.reflect.InvocationTargetException: null
at java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at org.springframework.boot.util.Instantiator.instantiate(Instantiator.java:143)
at org.springframework.boot.util.Instantiator.instantiate(Instantiator.java:127)
... 33 common frames omitted
Caused by: java.lang.IllegalArgumentException: Class must not be null
at org.springframework.util.Assert.notNull(Assert.java:201)
at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:730)
at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:704)
at org.springframework.cloud.vault.config.VaultConfigDataLoader.reconfigureLogger(VaultConfigDataLoader.java:388)
at org.springframework.cloud.vault.config.VaultConfigDataLoader.lambda$reconfigureLoggers$18(VaultConfigDataLoader.java:383)
at java.util.Arrays$ArrayList.forEach(Arrays.java:4390)
at org.springframework.cloud.vault.config.VaultConfigDataLoader.reconfigureLoggers(VaultConfigDataLoader.java:383)
at org.springframework.cloud.vault.config.VaultConfigDataLoader.<init>(VaultConfigDataLoader.java:109)
... 36 common frames omitted
Any ideas or suggestions to how I can debug it further or get past this? Many thanks PS: I don't have any issue when running my jar file directly
I was able to solve this by adding the following native hint to my project:
@NativeHint(
types = @TypeHint(
types = {
VaultConfigDataLocationResolver.class
},
typeNames = {
// These two taken from org.springframework.cloud.vault.config.VaultConfigDataLoader#reconfigureLoggers
"org.springframework.vault.core.lease.SecretLeaseContainer$LeaseRenewalScheduler",
"org.springframework.vault.core.lease.SecretLeaseEventPublisher$LoggingErrorListener"
}
)
)
Thank you @nbruno I tried your solution , Now the application start , but it's not able to retrieve the vault token , I'm having this error:
org.springframework.vault.VaultException: Cannot initialize PropertySource for secret at secret/enki-poc-v2/local; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.springframework.vault.support.VaultResponse]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.vault.support.VaultResponse` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
I tried adding a the class VaultResponse to the TypeHint , but I'm still having other issues
Recreating enki-poc-v2-native_poc-service_1 ... done
Attaching to enki-poc-v2-native_poc-service_1
poc-service_1 | 13:07:37.805 [main] INFO org.springframework.boot.SpringApplication - AOT mode enabled
poc-service_1 | 13:07:38.503 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
poc-service_1 | org.springframework.vault.VaultException: Cannot initialize PropertySource for secret at secret/enki-poc-v2/local; nested exception is java.lang.IllegalStateException: Token response is null
poc-service_1 | at org.springframework.cloud.vault.config.VaultConfigDataLoader.createLeasingPropertySourceFailFast(VaultConfigDataLoader.java:321)
poc-service_1 | at org.springframework.cloud.vault.config.VaultConfigDataLoader.loadConfigData(VaultConfigDataLoader.java:159)
poc-service_1 | at org.springframework.cloud.vault.config.VaultConfigDataLoader.load(VaultConfigDataLoader.java:140)
poc-service_1 | at org.springframework.cloud.vault.config.VaultConfigDataLoader.load(VaultConfigDataLoader.java:93)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:107)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:128)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:121)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:311)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:232)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102)
poc-service_1 | at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94)
poc-service_1 | at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102)
poc-service_1 | at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87)
poc-service_1 | at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
poc-service_1 | at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
poc-service_1 | at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
poc-service_1 | at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
poc-service_1 | at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:85)
poc-service_1 | at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:66)
poc-service_1 | at java.util.ArrayList.forEach(ArrayList.java:1541)
poc-service_1 | at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120)
poc-service_1 | at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114)
poc-service_1 | at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:65)
poc-service_1 | at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:338)
poc-service_1 | at org.springframework.boot.SpringApplication.run(SpringApplication.java:296)
poc-service_1 | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
poc-service_1 | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290)
poc-service_1 | at com.smarthome.enkipocv2native.EnkiPocV2NativeApplication.main(EnkiPocV2NativeApplication.java:29)
poc-service_1 | Caused by: java.lang.IllegalStateException: Token response is null
poc-service_1 | at org.springframework.util.Assert.state(Assert.java:76)
poc-service_1 | at org.springframework.vault.authentication.LoginTokenAdapter.lookupSelf(LoginTokenAdapter.java:96)
poc-service_1 | at org.springframework.vault.authentication.LoginTokenAdapter.augmentWithSelfLookup(LoginTokenAdapter.java:78)
poc-service_1 | at org.springframework.vault.authentication.LifecycleAwareSessionManager.doGetSessionToken(LifecycleAwareSessionManager.java:291)
poc-service_1 | at org.springframework.vault.authentication.LifecycleAwareSessionManager.getSessionToken(LifecycleAwareSessionManager.java:266)
poc-service_1 | at org.springframework.vault.core.VaultTemplate.lambda$getSessionInterceptor$1(VaultTemplate.java:253)
poc-service_1 | at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93)
poc-service_1 | at org.springframework.vault.client.RestTemplateBuilder.lambda$createTemplate$4(RestTemplateBuilder.java:239)
poc-service_1 | at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93)
poc-service_1 | at org.springframework.vault.client.VaultClients.lambda$createRestTemplate$0(VaultClients.java:122)
poc-service_1 | at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93)
poc-service_1 | at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:77)
poc-service_1 | at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
poc-service_1 | at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
poc-service_1 | at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:776)
poc-service_1 | at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711)
poc-service_1 | at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:334)
poc-service_1 | at org.springframework.vault.core.VaultTemplate.lambda$doRead$5(VaultTemplate.java:461)
poc-service_1 | at org.springframework.vault.core.VaultTemplate.doWithSession(VaultTemplate.java:448)
poc-service_1 | at org.springframework.vault.core.VaultTemplate.doRead(VaultTemplate.java:458)
poc-service_1 | at org.springframework.vault.core.VaultTemplate.read(VaultTemplate.java:353)
poc-service_1 | at org.springframework.vault.core.lease.SecretLeaseContainer.doGetSecrets(SecretLeaseContainer.java:645)
poc-service_1 | at org.springframework.vault.core.lease.SecretLeaseContainer.doStart(SecretLeaseContainer.java:390)
poc-service_1 | at org.springframework.vault.core.lease.SecretLeaseContainer.start(SecretLeaseContainer.java:380)
poc-service_1 | at org.springframework.vault.core.lease.SecretLeaseContainer.addRequestedSecret(SecretLeaseContainer.java:343)
poc-service_1 | at org.springframework.vault.core.env.LeaseAwareVaultPropertySource.loadProperties(LeaseAwareVaultPropertySource.java:176)
poc-service_1 | at org.springframework.vault.core.env.LeaseAwareVaultPropertySource.<init>(LeaseAwareVaultPropertySource.java:161)
poc-service_1 | at org.springframework.vault.core.env.LeaseAwareVaultPropertySource.<init>(LeaseAwareVaultPropertySource.java:119)
poc-service_1 | at org.springframework.cloud.vault.config.VaultConfigDataLoader.createLeasingPropertySource(VaultConfigDataLoader.java:287)
poc-service_1 | at org.springframework.cloud.vault.config.VaultConfigDataLoader.createLeasingPropertySourceFailFast(VaultConfigDataLoader.java:310)
poc-service_1 | ... 28 common frames omitted
enki-poc-v2-native_poc-service_1 exited with code 1
I already checked the VaultToken it's Valid , when it's not I'm getting 403 . Maybe my configuration of TypeHint it's not good , I'm new to this, I think Spring native still don't know my class "VaultResponse" Any Idea ?
@OlgaMaciaszek Could you please check if we should added related hints?
See another related error reported via #1423 that I closed as a duplicate.
Hi, what about progress?
Backlog milestone means we ans we are not actively working on this, and that we will re evaluate fixing that in Spring Boot 3 timeframe.
Spring Native is now superseded by Spring Boot 3 official native support, see the related reference documentation for more details.
As a consequence, I am closing this issue, and recommend trying your use case with latest Spring Boot 3 version. If you still experience the issue reported here, please open an issue directly on the related Spring project (Spring Framework, Data, Security, Boot, Cloud, etc.) with a reproducer.
Thanks for your contribution on the experimental Spring Native project, we hope you will enjoy the official native support introduced by Spring Boot 3.