Skip to content

Instantly share code, notes, and snippets.

@mp911de
Created December 2, 2016 21:24
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mp911de/17f550ffecdc9e8f22061bfdf896bbb4 to your computer and use it in GitHub Desktop.
Save mp911de/17f550ffecdc9e8f22061bfdf896bbb4 to your computer and use it in GitHub Desktop.
Using Spring Cloud Vault Config to get a token for Spring Cloud Vault Consul Config
# 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);
}
}
@krisiye
Copy link

krisiye commented Mar 3, 2021

@mp911de - Is there version of this workaround that works for Spring boot 2.4 that does not use legacy bootstrap processing?

@mp911de
Copy link
Author

mp911de commented Mar 4, 2021

That was actually addressed by spring-cloud/spring-cloud-vault#393 and by importing Vault config through Boot's 2.4 ConfigData API.

@krisiye
Copy link

krisiye commented Mar 5, 2021

@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')

@mp911de
Copy link
Author

mp911de commented Mar 8, 2021

This is a known bug, see spring-cloud/spring-cloud-vault#580.

@krisiye
Copy link

krisiye commented Mar 8, 2021

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment