spring-vault icon indicating copy to clipboard operation
spring-vault copied to clipboard

VaultPropertySource additonal property transformers

Open LeMakhno opened this issue 1 month ago • 10 comments

LeMakhno avatar Nov 24 '25 15:11 LeMakhno

Because there are no tests showing the usage really, this pull request is really difficult to judge in terms of usability. Based on your contribution, here are usage examples of which the first one is based on the current changes while the subsequent ones are variants of various ideas:

@PropertyMapping Variant:

@VaultPropertySource(value = "secret/myapp/config", propertyMappings = {
		@PropertyMapping(from = "db.username", to = "spring.datasource.username"),
		@PropertyMapping(from = "db.password", to = "spring.datasource.password")
})

String-based property mappings:

@VaultPropertySource(value = "secret/myapp/config", propertyMappings = {
		"db.username=spring.datasource.username",
		"db.password=spring.datasource.password"})

@VaultPropertySource(value = "secret/myapp/config"
		    propertyMappings = "username=spring.datasource.username,password=spring.datasource.password"
)

External property file property mappings:

@VaultPropertySource(
    value = "secret/myapp/config",
    mappings = "classpath:vault-mappings.properties"
)

JSON-like property mappings:

@VaultPropertySource(
    value = "secret/myapp/config",
		mappings = """
				{ 
					'spring.datasource.username': '${db.username}',
					'spring.datasource.password': '${db.password}'
				}
				"""
)

mp911de avatar Dec 08 '25 10:12 mp911de

Circling back to Spring Cloud Vault (as there is quite elaborate support for property mapping):

RequestedSecret rotating = RequestedSecret.rotating("secret/rotating");
PropertyNameTransformer transformer = new PropertyNameTransformer();
transformer.addKeyTransformation("db.username", "spring.datasource.username");
// …

configurer.add(RequestedSecret.rotating("database/mysql/creds/readonly"), transformer);

What's the reason for you using @VaultPropertySource over VaultConfigurer via Spring Cloud Vault?

mp911de avatar Dec 08 '25 11:12 mp911de

I'd like to keep it declarative, as it supposed to be in Spring, instead of describing secrets in code. My pull request enhances annotation based approach with feature of custom prop name mapping.

LeMakhno avatar Dec 08 '25 11:12 LeMakhno

Approach with @PropertyMapping is the most elegant in my opinion.

LeMakhno avatar Dec 08 '25 11:12 LeMakhno

VaultConfigurer configuration does not seem to work, spring 3.5.8, springCloudVersion 2025.0.0. Tried declaring @Component, @Configuration of this type, spring does not call the method addSecretBackends i override to configure vault.

LeMakhno avatar Dec 08 '25 12:12 LeMakhno

Configuration is initialized before the context is started as configuration is required to control bean registrations. Here's the documentation showing how to configure Spring Vault through the config data API: https://docs.spring.io/spring-cloud-vault/reference/secret-backends.html#vault.config.backends.configurer

mp911de avatar Dec 08 '25 13:12 mp911de

I did as specified in documentation, there are issues:

  1. there is no method addBootstrapper on SpringApplication anymore (spring boot 3.5.8)
  2. the closest where i can put VaultConfigurer is through app.addBootstrapRegistryInitializer(VaultBootstrapper.fromConfigurer(new MyVaultConfigurer()));, in this case the overridden method addSecretBackends is not being called.

Could you suggest something?

LeMakhno avatar Dec 08 '25 13:12 LeMakhno

Good catch about addBootstrapRegistryInitializer vs. addBootstrapper, we need to fix that in our documentation. Right now, the customizer is being called when importing Vault through the config data API by setting e.g. spring.config.import=vault: as it serves primarily as configuration hook for mounting secret backends available on the class path (e.g. databases, key/value). These can be disabled via SecretBackendConfigurer.registerDefaultKeyValueSecretBackends(false) for selective imports.

mp911de avatar Dec 09 '25 09:12 mp911de

Sorry, can't make it work. Did as you suggested in last comment, my VaultConfigurer is not called anyways. All attempts to configure vault using annotation @VaultPropertySource and properties file end with

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cloud.vault.config.VaultAutoConfiguration]: No default constructor found

My use case is renewable secret

LeMakhno avatar Dec 09 '25 15:12 LeMakhno

The constructor exception is part of why @VaultProperties does not play nicely with Spring Boot, see https://github.com/spring-cloud/spring-cloud-vault/issues/642 for further explanation.

I see the appetite for annotation-based configuration of Vault property sources with Spring Boot applications, maybe that's an angle we should spend a bit more time on and consider how such an arrangement could be enabled with the config data API. However, configuration class parsing happens after Config Data is loaded so this cycle currently doesn't allow for a simple solution.

mp911de avatar Dec 10 '25 09:12 mp911de