-
-
Save mp911de/17f550ffecdc9e8f22061bfdf896bbb4 to your computer and use it in GitHub Desktop.
# Bootstrap Configuration: META-INF/spring.factories | |
org.springframework.cloud.bootstrap.BootstrapConfiguration=example.infrastructure.VaultForConsulBootstrapConfiguration |
/* | |
* Copyright 2016 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 example.infrastructure; | |
import java.util.Collections; | |
import org.springframework.beans.BeansException; | |
import org.springframework.beans.factory.InitializingBean; | |
import org.springframework.boot.autoconfigure.AutoConfigureOrder; | |
import org.springframework.cloud.vault.config.consul.VaultConsulProperties; | |
import org.springframework.context.ApplicationContext; | |
import org.springframework.context.ApplicationContextAware; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.core.env.ConfigurableEnvironment; | |
import org.springframework.core.env.MapPropertySource; | |
import org.springframework.vault.core.VaultOperations; | |
import org.springframework.vault.core.env.VaultPropertySource; | |
/** | |
* @author Mark Paluch | |
*/ | |
@Configuration | |
@AutoConfigureOrder(1) | |
public class VaultForConsulBootstrapConfiguration implements ApplicationContextAware, | |
InitializingBean { | |
private ApplicationContext applicationContext; | |
@Override | |
public void setApplicationContext(ApplicationContext applicationContext) | |
throws BeansException { | |
this.applicationContext = applicationContext; | |
} | |
@Override | |
public void afterPropertiesSet() { | |
ConfigurableEnvironment ce = (ConfigurableEnvironment) applicationContext | |
.getEnvironment(); | |
if (ce.getPropertySources().contains("consul-token")) { | |
return; | |
} | |
VaultOperations vaultOperations = applicationContext | |
.getBean(VaultOperations.class); | |
VaultConsulProperties consulProperties = applicationContext | |
.getBean(VaultConsulProperties.class); | |
VaultPropertySource vaultPropertySource = new VaultPropertySource( | |
vaultOperations, String.format("%s/creds/%s", | |
consulProperties.getBackend(), consulProperties.getRole())); | |
MapPropertySource mps = new MapPropertySource("consul-token", | |
Collections.singletonMap("spring.cloud.consul.token", | |
vaultPropertySource.getProperty("token"))); | |
ce.getPropertySources().addFirst(mps); | |
} | |
} |
That was actually addressed by spring-cloud/spring-cloud-vault#393 and by importing Vault config through Boot's 2.4 ConfigData API.
@mp911de - With spring boot's 2.4 configData API and a configuration such as spring.config.import=vault://,consul://
we run into the issue where the acl-token (for consul) is not available before we try to import from consul resulting in a 403 right away. Confirmed this by providing the acl-token as a -D arg.
The above workaround worked great for legacy processing with bootstrap but does not work for configData API anymore. Can you please review this and let me know if this is a bug? Thanks! Sample stack trace attached below:
16:13:34.199 [main] DEBUG org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.boot.context.config.ConfigDataResourceNotFoundException: Config data resource '[ConsulConfigDataResource@2bfc268b context = 'local/spring-boot-example/spring-boot-example,local.properties', optional = true, properties = [ConsulConfigProperties@2f8dad04 enabled = true, prefix = 'local/spring-boot-example', defaultContext = 'application', profileSeparator = ',', format = FILES, dataKey = 'data', aclToken = [null], watch = [ConsulConfigProperties.Watch@29e495ff waitTime = 55, enabled = true, delay = 1000], failFast = true, name = 'spring-boot-example']]' via location 'consul://' cannot be found
at org.springframework.boot.context.config.ConfigDataResourceNotFoundException.withLocation(ConfigDataResourceNotFoundException.java:97)
at org.springframework.boot.context.config.ConfigDataImporter.handle(ConfigDataImporter.java:133)
at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:124)
at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:82)
at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:121)
at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:310)
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:235)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:97)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:100)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:86)
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:82)
at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:362)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at com.hmhco.example.springboot.Application.main(Application.java:21)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.springframework.cloud.consul.config.ConsulPropertySources$PropertySourceNotFoundException: OperationException{statusCode=403, statusMessage='Forbidden', statusContent='Permission denied'}
at org.springframework.cloud.consul.config.ConsulPropertySources.createPropertySource(ConsulPropertySources.java:135)
at org.springframework.cloud.consul.config.ConsulConfigDataLoader.load(ConsulConfigDataLoader.java:44)
at org.springframework.cloud.consul.config.ConsulConfigDataLoader.load(ConsulConfigDataLoader.java:29)
at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:103)
at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:118)
... 29 common frames omitted
Caused by: com.ecwid.consul.v1.OperationException: OperationException(statusCode=403, statusMessage='Forbidden', statusContent='Permission denied')
This is a known bug, see spring-cloud/spring-cloud-vault#580.
@mp911de - This issue is different in that you will only see this once you enable the vault secret backend for consul with spring-cloud/spring-cloud-vault#580. It's about making the consul token (from vault based on a Role) available for the consul data loader to use.
@mp911de - Is there version of this workaround that works for Spring boot 2.4 that does not use legacy bootstrap processing?