Closed FWinkler79 closed 4 years ago
After 4-5 days trying to implement this, I found a workaround with the following configuration
Spring cloud version: Greenwich.SR3 Spring Cloud Config Server: 2.1.4.RELEASE Spring boot: 2.1.8
spring:
application:
name: config-server
cloud:
config:
server:
bootstrap: true
composite:
- type: vault
kv-version: 2
token: VAULT_TOKEN
vault:
token: VAULT_TOKEN
profiles:
active: composite
main:
allow-bean-definition-overriding: true
server:
port: 8888
spring:
cloud:
config:
server:
composite:
- type: git
uri: GIT_URI
username: ${git.username}
password: ${git.password}
The only problem is that, when i query the config server at its default profile, the vault configuration gets repeated
If anyone knows how to prevent the above or the right way to do this, it would still be very much appreciated
Hi @deciojr,
great that you had a look at it, it's much appreciated. I am just not sure we should call it a "workaround", since having the vault configuration duplicated is not really clean and kind of unexpected. What do you think?
Cheers!
I agree. English isn't my primary language, so I couldn't think of any other word at the time.
I am wondering if this is something that the Spring team would be willing to fix.
Generally, I see a benefit in a config-server being able to bootstrap its own config from the very GitHub repo it uses to serve other services' configs from. And it's also obvious that an integration with a password Vault is a great benefit.
However, this bug makes that combination impossible to use - when I would have thought this should be the preferred setup.
How likely is it that this is getting fixed? Just asking, since otherwise we will need to go for a different, less optimal solution.
There have been new options for authenticating vault. See #1475. Can this be used here?
Thanks for the hint. Unfortunately that does not help here. In the meantime I think I found the bug that causes this issue.
If evth. is configured right (i.e. as documented) I keep getting the error:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'configTokenProvider', defined in class path resource [org/springframework/cloud/config/server/config/VaultConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/cloud/config/server/config/EnvironmentRepositoryConfiguration$DefaultConfigTokenProvider.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2020-01-14 18:25:27.739 DEBUG [config-server,,,] 99242 --- [ main] .c.l.ClasspathLoggingApplicationListener : Application failed to start with classpath: unknown
2020-01-14 18:25:27.739 ERROR [config-server,,,] 99242 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'configTokenProvider' defined in class path resource [org/springframework/cloud/config/server/config/VaultConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.cloud.config.server.config.VaultConfiguration; factoryMethodName=configTokenProvider; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/cloud/config/server/config/VaultConfiguration.class]] for bean 'configTokenProvider': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.cloud.config.server.config.EnvironmentRepositoryConfiguration$DefaultConfigTokenProvider; factoryMethodName=configTokenProvider; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/cloud/config/server/config/EnvironmentRepositoryConfiguration$DefaultConfigTokenProvider.class]] bound.
at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:927) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:287) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:144) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:337) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:242) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:140) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:206) ~[spring-cloud-context-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:117) ~[spring-cloud-context-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:74) ~[spring-cloud-context-2.2.1.RELEASE.jar:2.2.1.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:76) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:53) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:345) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at com.equalities.cloud.config.server.ConfigServer.main(ConfigServer.java:17) ~[classes/:na]
So I checked why this is the case, and found that there are two classes involved, one of which is not correct:
EnvironmentRepositoryConfiguration
imports VaultConfiguration
, and expects that it defines a bean named configTokenProvider
. In case that bean is not defined, EnvironmentRepositoryConfiguration
will declare its default fallback like this:
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ConfigTokenProvider.class)
protected static class DefaultConfigTokenProvider {
@Bean
public ConfigTokenProvider configTokenProvider(
ObjectProvider<HttpServletRequest> httpRequest) {
return new HttpRequestConfigTokenProvider(httpRequest);
}
However, since the fallback is declared inside a static inner class, Spring evaluates that first, thus not giving VaultConfiguration
a chance to provide its (proper) configTokenProvider
.
This causes the error, and the default configTokenProvider
simply does not work.
Note: this could even be a problem in other cases as well, as the list of imported configurations on EnvironmentRepositoryConfiguration
is quite extensive.
A possible fix should be to change EnvironmentRepositoryConfiguration
to not declare the fallback configTokenProvider
from within an inner configuration class, but via a @Bean
method like this:
// all @Imports here...
public class EnvironmentRepositoryConfiguration {
...
@Bean
@ConditionalOnMissingBean(ConfigTokenProvider.class)
public ConfigTokenProvider configTokenProvider(ObjectProvider<HttpServletRequest> httpRequest) {
return new HttpRequestConfigTokenProvider(httpRequest);
}
...
}
I was able to reproduce the erroneous behaviour in a test rig given here.
Is there a chance this can be fixed?
mark yours as @Primary
?
PRs welcome.
Since there is no bean of mine involved, but only framework beans that I cannot mark nor re-declare, I cannot mark anything as @Primary
.
I created a PR that fixes this issue, so that the intended setup will work. If the PR is merged, I will add a final description here, that shows the setup.
I tested this in my local environment, using this project setup.
Hi there,
I have inspected the following (somewhat related) issues, but none of them solves the problem I am experiencing:
1393
1446
1014
1060
984
Some specs of my application:
I tried several setups, which are described below. I could not get either of them working, thus leaving me stuck for now. Help or advice is greatly appreciated.
Intended Setup:
My setup is as follows:
bootstrap.yml
havingspring.cloud.config.server.bootstrap: true
composite
environment repository setup.The composite configuration looks as follows:
When I run
config-server
with this setup, I get the following error:So I tried what was suggested in #1446, i.e. to add
spring.cloud.config.server.vault.token
Option 1:
As a result, I get the following error:
Option 2:
As a result, I get the following error:
Alternative Setup:
I also tried without
composite
:In this setup I cannot get it to work no matter whether the
spring.cloud.config.server.vault.token
is set or not - getting the same kind of exceptions as above.Sample
You can find a sample where this is shown here.
To reproduce:
./scripts/startDevVault.sh