spring-cloud / spring-cloud/spring-cloud-vault
Vault Namespace Login for Secret Sharing in non Hierarchical Relationship
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 291
- Forks
- 152
- Avg merge
- 11h 24m
- Merged PRs (30d)
- 3
Description
Problem Description
With the release of Vault 1.13.0 it's possible to share secrets between namespaces without an hierachical relationship.
See documentation.
For Auth Methods (other than Token, e.g. Kubernetes) the Namespace is required for the login.
For importing secrets without the namespace a full path is needed.
If the namespace is set in the vault configuration the 'X-Vault-Namespace' header is set for every request.
Therefore its not possible to read secrets with an full qualified path.
Desired Solution
It would be nice to set the namespace for the login only.
spring:
cloud:
vault:
login-namespace: 'MY-DOMAIN-NAMESPACE'
So we could reference the secrets like:
spring:
config:
import:
- "optional:vault://'MY-DOMAIN-NAMESPACE/kv2/secret1"
- "optional:vault://'OTHER-DOMAIN-NAMESPACE/kv2/other-secret"
Workaround
In order to make this possible we found following workaround:
Register a custome WebClientFactory in the Application Class:
public static void main(String[] args) throws GeneralSecurityException, IOException {
SpringApplication application = new SpringApplication(Application.class);
application.addBootstrapRegistryInitializer(registry -> registry.register(WebClientFactory.class, CustomVaultSupplier .getWebClientFactorySupplier("MY-DOMAIN-NAMESPACE")));
application.run(args);
}
Creating an CustomVaultWebClientFactory:
public class CustomVaultWebClientFactory implements WebClientFactory {
private final ClientHttpConnector connector;
private final Function<ClientHttpConnector, WebClientBuilder> builderFunction;
CustomVaultWebClientFactory(ClientHttpConnector connector, Function<ClientHttpConnector, WebClientBuilder> builderFunction) {
this.connector = connector;
this.builderFunction = builderFunction;
}
@Override
public WebClient create(@Nullable Consumer<WebClientBuilder> customizer) {
WebClientBuilder builder = builderFunction.apply(connector);
if (customizer != null) {
customizer.accept(builder);
}
return builder.build();
}
}
Adding an ExchangeFilterFunction (Interceptor) to the (Kubernetes) auth method:
public class CustomVaultSupplier {
public static BootstrapRegistry.InstanceSupplier<WebClientFactory> getWebClientFactorySupplier(String loginNamespace) {
return context -> new CustomVaultWebClientFactory (context.get(VaultReactiveAutoConfiguration.ClientHttpConnectorWrapper.class).getConnector(), (connector) -> {
VaultEndpoint endpoint = VaultEndpoint.create(context.get(VaultProperties.class).getHost(), context.get(VaultProperties.class).getPort());
endpoint.setScheme(context.get(VaultProperties.class).getScheme());
return WebClientBuilder.builder().filter(getKubernetesLoginNamespaceFilter(context.get(VaultProperties.class).getKubernetes().getKubernetesPath(), loginNamespace))
.endpointProvider(SimpleVaultEndpointProvider.of(endpoint));
});
}
private static ExchangeFilterFunction getKubernetesLoginNamespaceFilter(String kubernetesPath, String loginNamespace) {
return (clientRequest, nextFilter) -> {
if (clientRequest.url().toString().contains(String.format("auth/%s/login", kubernetesPath))) {
ClientRequest newRequest = ClientRequest.from(clientRequest).header("X-Vault-Namespace", loginNamespace).build();
return nextFilter.exchange(newRequest);
}
return nextFilter.exchange(clientRequest);
};
}
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the WebClientFactory setup, VaultProperties, VaultReactiveAutoConfiguration, and the Kubernetes auth method shown in the workaround. Verify how the login request and config import requests set X-Vault-Namespace; done means a login-only namespace can be configured while fully qualified secret paths continue to address other namespaces.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- authentication, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100