Connect Azure Spring Apps to Key Vault using managed identities

Note

Azure Spring Apps is the new name for the Azure Spring Cloud service. Although the service has a new name, you'll see the old name in some places for a while as we work to update assets such as screenshots, videos, and diagrams.

This article applies to: ✔️ Java ❌ C#

This article shows you how to create a system-assigned or user-assigned managed identity for an app deployed to Azure Spring Apps and use it to access Azure Key Vault.

Azure Key Vault can be used to securely store and tightly control access to tokens, passwords, certificates, API keys, and other secrets for your app. You can create a managed identity in Microsoft Entra ID, and authenticate to any service that supports Microsoft Entra authentication, including Key Vault, without having to display credentials in your code.

The following video describes how to manage secrets using Azure Key Vault.


Prerequisites

  • An Azure subscription. If you don't have a subscription, create a free account before you begin.
  • Azure CLI, version 2.55.0 or higher.

Provide names for each resource

Create variables to hold the resource names by using the following commands. Be sure to replace the placeholders with your own values.

export LOCATION=<location>
export RESOURCE_GROUP=myresourcegroup
export SPRING_APPS=myasa
export APP=springapp-system
export KEY_VAULT=<your-keyvault-name>

Create a resource group

A resource group is a logical container into which Azure resources are deployed and managed. Create a resource group to contain both the Key Vault and Spring Cloud using the az group create command, as shown in the following example:

az group create --name ${RESOURCE_GROUP} --location ${LOCATION}

Set up your Key Vault

To create a Key Vault, use the az keyvault create command, as shown in the following example:

Important

Each Key Vault must have a unique name.

az keyvault create \
    --resource-group ${RESOURCE_GROUP} \
    --name ${KEY_VAULT}

Use the following command to show the app URL and then make a note of the returned URL, which is in the format https://${KEY_VAULT}.vault.azure.net. Use this value in the following step.

az keyvault show \
    --resource-group ${RESOURCE_GROUP} \
    --name ${KEY_VAULT} \
    --query properties.vaultUri --output tsv

You can now place a secret in your Key Vault by using the az keyvault secret set command, as shown in the following example:

az keyvault secret set \
    --vault-name ${KEY_VAULT} \
    --name "connectionString" \
    --value "jdbc:sqlserver://SERVER.database.windows.net:1433;database=DATABASE;"

Create Azure Spring Apps service and app

After you install all corresponding extensions, use the following command to create an Azure Spring Apps instance:

az extension add --upgrade --name spring
az spring create \
    --resource-group ${RESOURCE_GROUP} \
    --sku Enterprise \
    --name ${SPRING_APPS}

The following example creates the app with a system-assigned managed identity, as requested by the --system-assigned parameter:

az spring app create \
    --resource-group ${RESOURCE_GROUP} \
    --service ${SPRING_APPS} \
    --name ${APP} \
    --assign-endpoint true \
    --system-assigned
export MANAGED_IDENTITY_PRINCIPAL_ID=$(az spring app show \
    --resource-group ${RESOURCE_GROUP} \
    --service ${SPRING_APPS} \
    --name ${APP} \
    --query identity.principalId --output tsv)
az extension add --upgrade --name spring
az spring create \
    --resource-group ${RESOURCE_GROUP} \
    --name ${SPRING_APPS}

The following example creates an app named springapp with a system-assigned managed identity, as requested by the --system-assigned parameter.

az spring app create \
    --resource-group ${RESOURCE_GROUP} \
    --service ${SPRING_APPS} \
    --name ${APP} \
    --assign-endpoint true \
    --runtime-version Java_17 \
    --system-assigned
export MANAGED_IDENTITY_PRINCIPAL_ID=$(az spring app show \
    --resource-group ${RESOURCE_GROUP} \
    --service ${SPRING_APPS} \
    --name ${APP} \
    --query identity.principalId --output tsv)

Grant your app access to Key Vault

Use the following command to grant proper access in Key Vault for your app:

az keyvault set-policy \
    --name ${KEY_VAULT} \
    --object-id ${MANAGED_IDENTITY_PRINCIPAL_ID} \
    --secret-permissions set get list

Note

For system-assigned managed identity, use az keyvault delete-policy --name ${KEY_VAULT} --object-id ${MANAGED_IDENTITY_PRINCIPAL_ID} to remove the access for your app after system-assigned managed identity is disabled.

Build a sample Spring Boot app with Spring Boot starter

This app has access to get secrets from Azure Key Vault. Use the Azure Key Vault Secrets Spring boot starter. Azure Key Vault is added as an instance of Spring PropertySource. Secrets stored in Azure Key Vault can be conveniently accessed and used like any externalized configuration property, such as properties in files.

  1. Use the following command to generate a sample project from start.spring.io with Azure Key Vault Spring Starter.

    curl https://start.spring.io/starter.tgz -d dependencies=web,azure-keyvault -d baseDir=springapp -d bootVersion=3.2.1 -d javaVersion=17 -d type=maven-project | tar -xzvf -
    
  2. Specify your Key Vault in your app.

    cd springapp
    vim src/main/resources/application.properties
    
  3. To use managed identity for an app deployed to Azure Spring Apps, add properties with the following content to the src/main/resources/application.properties file.

    spring.cloud.azure.keyvault.secret.property-sources[0].endpoint=<your-keyvault-url>
    spring.cloud.azure.keyvault.secret.property-sources[0].credential.managed-identity-enabled=true
    

    Note

    You must add the key vault URL in the application.properties file as shown previously. Otherwise, the key vault URL may not be captured during runtime.

  4. Update src/main/java/com/example/demo/DemoApplication.java with the following code example. This code retrieves the connection string from the Key Vault.

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    public class DemoApplication implements CommandLineRunner {
    
        @Value("${connectionString}")
        private String connectionString;
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
        @GetMapping("get")
        public String get() {
            return connectionString;
        }
    
        public void run(String... args) throws Exception {
            System.out.println(String.format("\nConnection String stored in Azure Key Vault:\n%s\n",connectionString));
        }
    }
    

    If you open the pom.xml file, you can see the spring-cloud-azure-starter-keyvault dependency, as shown in the following example:

    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-keyvault</artifactId>
    </dependency>
    
  1. Use the following command to deploy your app to Azure Spring Apps:

    az spring app deploy \
        --resource-group ${RESOURCE_GROUP} \
        --service ${SPRING_APPS} \
        --name ${APP} \
        --source-path
    
  1. Use the following command to deploy your app to Azure Spring Apps:

    az spring app deploy \
        --resource-group ${RESOURCE_GROUP} \
        --service ${SPRING_APPS} \
        --name ${APP} \
        --source-path \
        --build-env BP_JVM_VERSION=17
    
  1. To test your app, access the public endpoint or test endpoint by using the following command:

    curl https://${SPRING_APPS}-${APP}.azuremicroservices.io/get
    

    The following message is returned in the response body: jdbc:sqlserver://SERVER.database.windows.net:1433;database=DATABASE;.

Clean up resources

Use the following command to delete the entire resource group, including the newly created service instance:

az group delete --name ${RESOURCE_GROUP} --yes

Next steps