I would like to replace spring.datasource.password with a password from azure keyvault.
I have a project based on spring boot:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version>
I am using dependencies :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.13.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-keyvault</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-keyvault-secrets</artifactId>
</dependency>
I have created the config:
@Configuration
public class KeyVaultConfig {
@Bean
SecretClient secretClient(
@Value("${spring.cloud.azure.keyvault.secret.endpoint}") String keyVaultUri,
@Value("${azure.client.id}") String clientId,
@Value("${azure.client.secret}") String clientSecret,
@Value("${azure.tenant.id}") String tenantId) {
ClientSecretCredential credential = new ClientSecretCredentialBuilder()
.clientId(clientId)
.clientSecret(clientSecret)
.tenantId(tenantId)
.build();
return new SecretClientBuilder()
.vaultUrl(keyVaultUri)
.credential(credential)
.buildClient();
}
}
This config works fine when I do not want to inject properties. For instance this code:
@GetMapping("/status")
public String status() {
log.info("generating status page");
return "read from keyvault: " + keyVaultService.getSecret("psur-db-url");
}
works just fine. So this proves that the credentials are set correctly.
But when I try to use this setup with combination of properties:
spring.cloud.azure.compatibility-verifier.enabled=false
spring.cloud.azure.keyvault.secret.property-source-enabled=true
spring.datasource.url={my-secret-db-url}
spring.datasource.username=user
spring.datasource.password={my-secret-db-password}
I have tried different configurations in properties as well as configuring the ClientSecretCredential in different way. But I never managed the properties to be injected.
Currently I am getting exception
Caused by: java.lang.IllegalArgumentException: URL must start with 'jdbc'
which suggest that the url was never replaced.
I am suspecting that the SecretClient is not created with my config, because when I put a breakpoint there it is never reached. But this is just a guess.
Am I missing something in my config? Or maybe the configuration is wrong?
2
Answers
The solution which currently works for me is:
I have removed the dependency to spring-cloud-azure-starter-keyvault-secrets.
I have entirely removed the KeyVaultConfig class. I am using the auto configred SecretClient (according to https://learn.microsoft.com/en-us/azure/developer/java/sdk/identity-azure-hosted-auth#default-azure-credential). I have setup environment variables in my Intellij according to (https://learn.microsoft.com/en-us/azure/developer/java/sdk/identity-azure-hosted-auth#environment-variables)
Although this works I would prefere not to need to setup the environment variables so I am still looking for a way to create my own SecurityClient, inject into the context and reuse while connecting to keyvault.
Solution nr 2:
I am using same pom.xml as in Solution nr 1, as well I do not define my own SecretClient. I am just setting the client, secret and tenant in properties file:
they will be used to create ClientSecretCredential which will be injected into SecretClient.
Another tip when dealing with similiar topic is to set the logging:
and look in logs for text containing: "Azure Identity =>"
For instance:
In that way you can understand if your config is working and what is happening under the hood.