azure-sdk-for-java icon indicating copy to clipboard operation
azure-sdk-for-java copied to clipboard

Azure Key Vault- How to use AzureCliCredential first when using spring.cloud.azure.keyvault.secret.property-sources[0].endpoint

Open lavercr opened this issue 1 year ago • 33 comments

Discussed in https://github.com/Azure/azure-sdk-for-java/discussions/38982

regarding this https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-key-vault#use-spring-key-vault-propertysource

Issue with spring-cloud-azure-starter-keyvault 5.9.1

Originally posted by lavercr February 28, 2024 There is a really large delay when using spring.cloud.azure.keyvault.secret.property-sources[0].endpoint The delay is more than 2 mins.

When I do this using AzureCliCredential directly my spring boot app loads and finds the key in seconds. How can I configure spring.cloud.azure.keyvault.secret.property-sources[0].endpoint to only use AzureCliCredential for authentication.

lavercr avatar Feb 28 '24 17:02 lavercr

using : springboot 3.2.2 sring-cloud-azure-dependencies 5.9.1 JavaSE-17 (OpenJDK 21.0.1) az cli 2.57.0 running on MacOS 14.3

lavercr avatar Feb 28 '24 17:02 lavercr

logs

 [2m2024-02-28T11:46:45.153-05:00 [0;39m  [32m INFO [0;39m  [35m34603 [0;39m  [2m--- [0;39m  [2m[           main] [0;39m  [2m [0;39m [36mm.p.s.SpringbootAzureKeyvaultApplication [0;39m  [2m: [0;39m Starting SpringbootAzureKeyvaultApplication using Java 21.0.1 with PID 34603 (/Users/lavercr/src/springboot-azure-keyvault/target/classes started by lavercr in /Users/lavercr/src/springboot-azure-keyvault)
 [2m2024-02-28T11:46:45.154-05:00 [0;39m  [32m INFO [0;39m  [35m34603 [0;39m  [2m--- [0;39m  [2m[           main] [0;39m  [2m [0;39m [36mm.p.s.SpringbootAzureKeyvaultApplication [0;39m  [2m: [0;39m No active profile set, falling back to 1 default profile: "default"
 [2m2024-02-28T11:46:45.642-05:00 [0;39m  [32m INFO [0;39m  [35m34603 [0;39m  [2m--- [0;39m  [2m[           main] [0;39m  [2m [0;39m [36mAbstractAzureServiceClientBuilderFactory [0;39m  [2m: [0;39m Will configure the default credential of type DefaultAzureCredential for class com.azure.identity.DefaultAzureCredentialBuilder.
 [2m2024-02-28T11:46:45.710-05:00 [0;39m  [32m INFO [0;39m  [35m34603 [0;39m  [2m--- [0;39m  [2m[           main] [0;39m  [2m [0;39m [36mm.p.s.SpringbootAzureKeyvaultApplication [0;39m  [2m: [0;39m Started **SpringbootAzureKeyvaultApplication in 141.667 seconds (process running for 142.235)**

lavercr avatar Feb 28 '24 17:02 lavercr

Hi @lavercr thanks for reaching out to us via this github issue. @saragluna @backwind1233 could you please follow up?

/cc @vcolin7

joshfree avatar Feb 29 '24 17:02 joshfree

Hi @lavercr , thanks for reaching out, Could help provide more info about how to use AzureCliCredential directly?

Netyyyy avatar Mar 01 '24 08:03 Netyyyy

If I create my own secretClient using AzureCliCredentialBuilder I can connect and pull passwords, but this way I have to write all the code. I would like to keep to the one liner that spring.cloud.azure.keyvault.secret.property-sources[0].endpoint gives us. This loads all the secrets and makes them available to the spring beans right away. If I do it myself it is more code, and the beans with secrets have to depend on this bean loading first. That gets messy quick.

@Configuration

public class AzureKeyVaultConfig {

    @Value("${spring.cloud.azure.keyvault.secret.uri}")
    private String keyVaultUri;

    @Bean
    SecretClient secretClient() {
        
        AzureCliCredential cliCredential = new AzureCliCredentialBuilder().build();

        // Azure SDK client builders accept the credential as a parameter.
        return new SecretClientBuilder()
           .vaultUrl(keyVaultUri)
           .credential(cliCredential)
           .buildClient();
         
    }
    
  
}

lavercr avatar Mar 01 '24 16:03 lavercr

Hi @lavercr , we don't support use AzureCliCredential directly, but you can add this code to only use AzureCliCredential for authentication.

    @Bean(name = DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME)
    TokenCredential tokenCredential( ) {
        return new AzureCliCredentialBuilder().build();
    }

Netyyyy avatar Mar 05 '24 02:03 Netyyyy

Hi, I don't understand your solution. Does this need a specific bean name ? I put a dummy name in and it still took a long time to respond.

lavercr avatar Mar 06 '24 22:03 lavercr

can you provide a more complete example that uses

spring.cloud.azure.keyvault.secret.property-sources[0].endpoint

and

  @Bean(name = DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME)
    TokenCredential tokenCredential( ) {
        return new AzureCliCredentialBuilder().build();
    }

lavercr avatar Mar 06 '24 22:03 lavercr

Hi @lavercr , could you help provide your minimal project?

Netyyyy avatar Mar 11 '24 08:03 Netyyyy

can you provide a more complete example that uses

spring.cloud.azure.keyvault.secret.property-sources[0].endpoint

and

  @Bean(name = DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME)
    TokenCredential tokenCredential( ) {
        return new AzureCliCredentialBuilder().build();
    }

can you provide me an example with this working. where spring.cloud.azure.keyvault.secret.property-sources uses TokenCredential tokenCredential( ) {

lavercr avatar Mar 13 '24 15:03 lavercr

create a springboot application with required azure dependencies

	<dependencies>
		<dependency>
			<groupId>com.azure.spring</groupId>
			<artifactId>spring-cloud-azure-starter-keyvault</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>com.azure.spring</groupId>
				<artifactId>spring-cloud-azure-dependencies</artifactId>
				<version>5.9.1</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

add this entry into your application.properties file that points to your working key vault spring.cloud.azure.keyvault.secret.property-sources[0].endpoint=[Your key vault url]

Add a secret to your vault called TestSecret

Setup your main class like this

package com.mbc.poc.springbootazurekeyvault;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootAzureKeyvaultApplication implements CommandLineRunner {

    @Value("${TestSecret}")
    private String testSecret;

    public static void main(String[] args) {
        SpringApplication.run(SpringbootAzureKeyvaultApplication.class, args);
    }

    @Override
    public void run(String... args) {

        System.out.println("TestSecret: " + testSecret);
    }
    
}

Determine how to use AzureCliCredentialBuilder in the authentication options first

lavercr avatar Mar 13 '24 16:03 lavercr

create a springboot application with required azure dependencies

	<dependencies>
		<dependency>
			<groupId>com.azure.spring</groupId>
			<artifactId>spring-cloud-azure-starter-keyvault</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>com.azure.spring</groupId>
				<artifactId>spring-cloud-azure-dependencies</artifactId>
				<version>5.9.1</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

add this entry into your application.properties file that points to your working key vault spring.cloud.azure.keyvault.secret.property-sources[0].endpoint=[Your key vault url]

Add a secret to your vault called TestSecret

Setup your main class like this

package com.mbc.poc.springbootazurekeyvault;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootAzureKeyvaultApplication implements CommandLineRunner {

    @Value("${TestSecret}")
    private String testSecret;

    public static void main(String[] args) {
        SpringApplication.run(SpringbootAzureKeyvaultApplication.class, args);
    }

    @Override
    public void run(String... args) {

        System.out.println("TestSecret: " + testSecret);
    }
    
}

Determine how to use AzureCliCredentialBuilder in the authentication options first

OK, I update your codes, hope this can help

package com.mbc.poc.springbootazurekeyvault;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME;

@SpringBootApplication
public class SpringbootAzureKeyvaultApplication implements CommandLineRunner {

    @Value("${TestSecret}")
    private String testSecret;

    public static void main(String[] args) {
        SpringApplication.run(SpringbootAzureKeyvaultApplication.class, args);
    }

    @Override
    public void run(String... args) {

        System.out.println("TestSecret: " + testSecret);
    }
    
    @Bean(name = DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME)
    TokenCredential tokenCredential( ) {
        return new AzureCliCredentialBuilder().build();
    }
}

Netyyyy avatar Mar 14 '24 01:03 Netyyyy

This doesn't work for myself. We have a similar issue where development is done on Azure VMs and would like to override the Default to CLI so that property placeholders also work.

Setting the SecretClientBuilder bean to CLI works inside Application but then the KV EnvironmentPostProcessor just uses the Default.

justinholmes avatar Mar 14 '24 17:03 justinholmes

I agree, this still seems to be using the default. I will see if I can find any logging category I can turn on.

Started SpringbootAzureKeyvaultApplication in 148.961 seconds (process running for 149.767)

lavercr avatar Mar 14 '24 17:03 lavercr

Unable to find any logging I can turn on to give clarity to what is delaying startup. I am still assuming it is because it trys AzureCliCredential last to connect to azure key vault.

lavercr avatar Mar 14 '24 17:03 lavercr

I believe there is a bug that needs fixing spring.cloud.azure.keyvault.secret.property-sources does not adhere to

    @Bean(name = DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME)
    TokenCredential tokenCredential( ) {
        return new AzureCliCredentialBuilder().build();
    }

lavercr avatar Mar 15 '24 14:03 lavercr

I've got it working using a custom/changed version KeyVaultEnvironmentPostProcessor, setting it to use CLI, using a custom prefix for the properties and adding it to spring.factories in META-INF. It's a nasty hack but best available right now. Loading takes ~10s.

justinholmes avatar Mar 15 '24 15:03 justinholmes

Can we confirm then that this is a bug. The fact that spring.cloud.azure.keyvault.secret.property-sources does not adhere to DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME

lavercr avatar Mar 15 '24 15:03 lavercr

any update?

lavercr avatar Mar 28 '24 02:03 lavercr

sorry for the late response and we will take a look about that

Netyyyy avatar Apr 01 '24 08:04 Netyyyy

@lavercr, this is because the environment processor at an earlier stage, before the default azure credential bean's initialization. To change this behavior, we need to do some refactor, but users need to register the DAC bean in another way.

saragluna avatar Apr 02 '24 07:04 saragluna

we need to do some refactor.. So there may be a fix coming our way ?

lavercr avatar Apr 02 '24 21:04 lavercr

we need to be able to control the order.

lavercr avatar Apr 08 '24 15:04 lavercr

@saragluna Can I have an update for this fix?

lavercr avatar Apr 09 '24 19:04 lavercr

Sorry, this update requires code refactoring, which we need more time to discuss.

Netyyyy avatar Apr 10 '24 03:04 Netyyyy

Do you have an update? This is going to be critical for our business unit in the next few months.

lavercr avatar Apr 22 '24 20:04 lavercr

any possible way to get more frequent updates? or are you able to give me a patch to work around this issue ?

lavercr avatar Apr 22 '24 20:04 lavercr

Not yet, but your contributions are welcome if you are interested

Netyyyy avatar Apr 24 '24 05:04 Netyyyy

Okay. I get it. I will have to live with it or create a bandage.

lavercr avatar Apr 25 '24 19:04 lavercr

@Netyyyy I have been asked for a date of fix. Please provide. This issue is holding up a security compliancy issue at our company. If there is another place or contact we can reach out to so we can get this fixed please let me know.
Thank you

lavercr avatar Apr 26 '24 16:04 lavercr