1
votes

I have a Java Spring boot application that just reads the secret from Azure Key Vault, below are steps used

  • Created an Application Registration

enter image description here

  • Copied the App Registration details

enter image description here

  • Generated Secret

enter image description here

  • Granted access on Azure Key Vault

enter image description here

and below is my Java Spring Boot application

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.contoso</groupId>
    <artifactId>keyvault</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>keyvault</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <azure.version>2.3.5</azure.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-keyvault-secrets-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.microsoft.azure</groupId>
                <artifactId>azure-spring-boot-bom</artifactId>
                <version>${azure.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

azure.keyvault.client-id=7a111923-xxxxxxxx-xxxxxx-31be31d233dd
azure.keyvault.client-key=gt_~k02yF_xxxxxx_vn3r1.GW
azure.keyvault.enabled=true
azure.keyvault.tenant-id=9cef136a-xxxx-xxxx-b7d3-d9d8a5a84182
azure.keyvault.uri=https://contosokvxxx.vault.azure.net/

KeyvaultApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;

@SpringBootApplication
@RestController
public class KeyvaultApplication {

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

  @GetMapping("get")
  public String get() {
    return connectionString;
  }

  @Value("${connectionString}")
  private String connectionString;

  public void run(String... varl) throws Exception {
    System.out.println(String.format("\nConnection String stored in Azure Key Vault:\n%s\n",connectionString));
  }  

}

It works and I could read the Secret from Azure Key Vault

enter image description here

so decided to remove the secrets from the application.properties and commented as below

#azure.keyvault.client-id=7a111923-1xxxxxxxx-31be31d233dd
#azure.keyvault.client-key=gt_~k02yF_xxxxxxxx-Hr6vn3r1.GW
azure.keyvault.enabled=true
#azure.keyvault.tenant-id=9cef136axxxxxxx-3-d9d8a5a84182
azure.keyvault.uri=https://contosokvxxx.vault.azure.net/

and added an Environment variable as shown below using setx

setx AzureServicesAuthConnectionString "RunAs=App;AppId=bb01c08b-xxxxxxxx-106;TenantId=9cef1-xxxxxxx-d9d8a5a84182;AppKey=xxxxxxxx-4Dpg-E3zrj~"

The project compiles without any isssues

>mvn clean compile package

but failed running

>mvn spring-boot:run

Error:

11:40:27.334 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Failed to configure KeyVault property source
        at com.microsoft.azure.keyvault.spring.KeyVaultEnvironmentPostProcessorHelper.addKeyVaultPropertySource(KeyVaultEnvironmentPostProcessorHelper.java:110)
        at com.microsoft.azure.keyvault.spring.KeyVaultEnvironmentPostProcessor.postProcessEnvironment(KeyVaultEnvironmentPostProcessor.java:47)

Caused by: java.lang.RuntimeException: Max retries 3 times exceeded. Error Details: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: no further information.
        at com.azure.core.http.policy.RetryPolicy.lambda$attemptAsync$1(RetryPolicy.java:116)
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:88)
2

2 Answers

1
votes

Please try to follow this sample.

It shows you how to use the Azure App Configuration service together with Azure Key Vault in a Java Spring application. It also sets the environment variables to connect key vault.

These Key Vault credentials are only used within your application. Your application authenticates directly with Key Vault using these credentials without involving the App Configuration service. The Key Vault provides authentication for both your application and your App Configuration service without sharing or exposing keys.

1
votes

Error Details: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: no further information.

The error means you could not connect to the Azure Instance Metadata Service endpoint, it is a REST Endpoint that is available at a well-known non-routable IP address (169.254.169.254), MSI use it to get the token, it can be accessed only from within the Azure service e.g. web app, VM, etc. Simply put, you could not use MSI(managed identity) in local.

To use MSI get secret from the azure keyvault, follow this to deploy your application to azure web app, enable the system-assigned identity or user-assigned identity, then remove the azure.keyvault.client-key from application.properties, change the azure.keyvault.client-id with the MSI's client id, add it to the access policy of the keyvault, details follow this.

azure.keyvault.client-id=56rqs994-0o66-43o3-9roo-8e3534d0cb23
azure.keyvault.enabled=true
azure.keyvault.tenant-id=72s988os-86s1-41ns-91ab-2q7pq011qo47
azure.keyvault.uri=https://contosokv.vault.azure.net/   

Reference - Tutorial: Reading a secret from Azure Key Vault in a Spring Boot application