0

I need to connect to Vault from my spring boot microservice. To get the vault token, the service needs to login to vault by providing username and password. Spring-vault integration doesn't support this behaviour by default.

I came across this SO question and tried the approach but it results in BeanDefinitionStoreException, as the bean named clientAuthentication is already defined.

Later I have referred this example and extend AbstractVaultConfiguration. Now my configuration hierarchy looks like the below:

@Configuration(proxyBeanMethods = false)
public abstract class AbstractVaultConfiguration implements ApplicationContextAware {
  public abstract VaultEndpoint vaultEndpoint();
  public abstract ClientAuthentication clientAuthentication();
  // other methods and bean definitions
}

@Configuration
public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration implements 
ApplicationContextAware {
  // other methods
}

public class VaultCustomConfig extends AbstractVaultConfiguration {
@Override
public VaultEndpoint vaultEndpoint() {
    return VaultEndpoint.create("https://vault-dev.net", 443);
}

@Override
public ClientAuthentication clientAuthentication() {
    //logic to fetch token
}
}

First two classes are provided by spring-vault. I have added the last one and also put entry in spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.test.configuration.VaultCustomConfig

The application is starting but getting 403 error. When I exclude EnvironmentVaultConfiguration from auto configuration, getting exceptions that many beans are not created(ex-vaultTemplate). I am able to contact vault API and fetch the token using RestTemplate. The challenge is setting that token before the app tries to contact vault(through spring-vault support).

Instead of overriding vault configuration, I tried setting an environment variable named vault.token which will be read by spring during start-up, but that is also not working(probably I missed something).

How can I override the built-in configuration and provide the token?

Antony Vimal Raj
  • 364
  • 3
  • 14
  • I am only experienced with the Vault bindings for Go, Python, Ruby, JS, and C++, but in a situation like this with unsupported endpoint bindings, then you should be able to just request against the API directly. You have defined the server endpoint already, so you should be able to make requests against the API for that server, receive JSON responses, and then parse the responses. See https://www.vaultproject.io/api-docs/system/auth#enable-auth-method and https://www.vaultproject.io/api-docs/auth/userpass. – Matthew Schuchard May 24 '22 at 13:25
  • @MattSchuchard I am able to access the API and fetch token. The challenge for me is, setting that token during app start-up before the app contact vault. – Antony Vimal Raj May 24 '22 at 14:00
  • Most bindings have a Vault client object with a `token` member. Can you not set that member to the token received from the `userpass` authentication POST? – Matthew Schuchard May 24 '22 at 14:12

2 Answers2

0

Spring Vault-related beans are initialized during bootstrap context, which is a parent context for the main application. That's why you need to use bootstrap.yml instead of application.yml to define properties. Check Spring Cloud Context: Application Context Services for more details.

Also you need to use org.springframework.cloud.bootstrap.BootstrapConfiguration in META-INF/spring.factories.

Alex
  • 4,987
  • 1
  • 8
  • 26
  • Vault properties are in bootstrap.properties. And I have updated the spring.factories as mentioned by you. Now getting `BeanDefinitionStoreException` with 'vaultTemplate' defined is overriden. – Antony Vimal Raj May 25 '22 at 07:31
  • @Antony Vimal Raj could you update your question with more details because currently it's hard to understand the root cause – Alex May 25 '22 at 16:37
0

Spring reads vault token from this property spring.cloud.vault.token. I have created a custom PropertySourceLocator and added the token:

public class VaultCustomPropertySourceLocator implements PropertySourceLocator {

@Override
public PropertySource<?> locate(Environment environment) {
    Properties props = new Properties();
    props.setProperty("spring.cloud.vault.token", getVaultAuthToken());
    PropertiesPropertySource ps = new PropertiesPropertySource("customPropsSource",props);
    return ps;
}

private String getVaultAuthToken() {
    // logic to fetch vault token
}
}
Antony Vimal Raj
  • 364
  • 3
  • 14