spring-cloud / spring-cloud-vault

Configuration Integration with HashiCorp Vault
http://cloud.spring.io/spring-cloud-vault/
Apache License 2.0
275 stars 152 forks source link

How to use a customized ClientAuthentication implementation #605

Closed tonysparks closed 3 years ago

tonysparks commented 3 years ago

Attempting to use JWT/OIDC means of authenticating to Vault. This option doesn't appear supported by spring-cloud-vault. I'm forced to create my own implementation of ClientAuthentication - which is easy enough, however, I can't seem to get spring-cloud-vault to recognize my implementation.

I created this configuration class:

@Configuration
public class VaultConfiguration extends AbstractVaultConfiguration {

    @Override
    public VaultEndpoint vaultEndpoint() {
      ... snip
    }

    @Override
    public ClientAuthentication clientAuthentication() {
        return new JwtAuthentication(this.getRestTemplateFactory().create(),
                String.format("%s/v1/auth/jwt/login", this.getEnvironment().getProperty("vault.uri")),
                this.getEnvironment().getProperty("platform-auth-url"),
                this.getEnvironment().getProperty("platform-client-id"),
                this.getEnvironment().getProperty("platform-client-secret"));
    }

}

Properties:

spring.cloud.vault.enabled=true
spring.cloud.vault.host=blah.com
spring.cloud.vault.port=443
spring.cloud.vault.scheme=https
spring.cloud.vault.uri=https://blah.com
spring.config.import=vault://
spring.cloud.vault.authentication=NONE
#spring.cloud.vault.authentication=APPROLE
#spring.cloud.vault.app-role.role=territory-service
#spring.cloud.vault.app-role.app-role-path=approle
#spring.cloud.vault.app-role.role-id=${ROLE_ID}
#spring.cloud.vault.app-role.secret-id=${ROLE_SECRET}
spring.cloud.vault.kv.enabled=true
spring.cloud.vault.kv.backend=enterprise-platform
spring.cloud.vault.kv.profile-separator=/
spring.cloud.vault.kv.default-context=territory-service/v1
spring.cloud.vault.kv.application-name=territory-service

Using:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-vault-config</artifactId>
    <version>3.0.3</version>
</dependency>

Errors: Complains about my custom VaultConfiguration defining vaultTemplate bean:

Invalid bean definition with name 'vaultTemplate' defined in class path resource

and not surprising, requests to Vault don't include a token:

Caused by: org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request: [{"errors":["missing client token"]}

When I remove my custom VaultConfiguration class and use APPROLE configuration, everything works fine.

Any ideas?

Thank you!

mp911de commented 3 years ago

Please do not subclass AbstravtVaultConfiguration. Instead, please provide a ClientAuthentication object through the BootstrapRegistryInitializer API. You just need to register the ClientAuthentication instance with the registry and Spring Cloud Vault will pick it up.

We were assuming that OIDC/JWT auth is a frontend technology that isn't commonly used between servers.

tonysparks commented 3 years ago

Thank you for the very quick reply!

I will look into the BootstrapRegistryInitializer - is there documentation or an example?

Regarding OIDC/JWT - for our use-case it simplifies our secret sharing with our API users. They only need to concern themselves with client credentials vs client credentials + vault credentials.

mp911de commented 3 years ago

We have only an initializer for providing a VaultConfigurer at

https://github.com/spring-cloud/spring-cloud-vault/blob/f976979a9f578b1358fe8803c02ac66d9d8a609f/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapper.java#L40-L45

We could provide another factory method accepting ClientAuthentication for easier use. Would you be interested in contributing your JWT authentication implementation to Spring Vault?

tonysparks commented 3 years ago

I appreciate the help! Here is my code, it probably isn't as robust as it should be -- but should serve as a good starting point.

Thanks!