-
-
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); | |
| } | |
| } |
@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.
That was actually addressed by spring-cloud/spring-cloud-vault#393 and by importing Vault config through Boot's 2.4 ConfigData API.