Tutorial: Secure Cognitive Service connection from .NET App Service using Key Vault

Azure App Service can use managed identities to connect to back-end services without a connection string, which eliminates connection secrets to manage and keeps your back-end connectivity secure in a production environment. For back-end services that don't support managed identities and still requires connection secrets, you can use Key Vault to manage connection secrets. This tutorial uses Cognitive Services as an example to show you how it's done in practice. When you're finished, you have an app that makes programmatic calls to Cognitive Services, without storing any connection secrets inside App Service.

Tip

Azure AI services do support authentication through managed identities, but this tutorial uses the subscription key authentication to demonstrate how you could connect to an Azure service that doesn't support managed identities from App Services.

Architecture diagram for tutorial scenario.

With this architecture:

  • Connectivity to Key Vault is secured by managed identities
  • App Service accesses the secrets using Key Vault references as app settings.
  • Access to the key vault is restricted to the app. App contributors, such as administrators, may have complete control of the App Service resources, and at the same time have no access to the Key Vault secrets.
  • If your application code already accesses connection secrets with app settings, no change is required.

What you will learn:

  • Enable managed identities
  • Use managed identities to connect to Key Vault
  • Use Key Vault references
  • Access Azure AI services

Prerequisites

Prepare your environment for the Azure CLI.

  • If you prefer to run CLI reference commands locally, install the Azure CLI. If you're running on Windows or macOS, consider running Azure CLI in a Docker container. For more information, see How to run the Azure CLI in a Docker container.

    • If you're using a local installation, sign in to the Azure CLI by using the az login command. To finish the authentication process, follow the steps displayed in your terminal. For other sign-in options, see Sign in with the Azure CLI.

    • When you're prompted, install the Azure CLI extension on first use. For more information about extensions, see Use extensions with the Azure CLI.

    • Run az version to find the version and dependent libraries that are installed. To upgrade to the latest version, run az upgrade.

Create app with connectivity to Azure AI services

  1. Create a resource group to contain all of your resources:

    # Save resource group name as variable for convenience
    groupName=myKVResourceGroup
    region=chinanorth
    
    az group create --name $groupName --location $region
    
  2. Create an Azure AI services resource. Replace <cs-resource-name> with a unique name of your choice.

    # Save resource name as variable for convenience. 
    csResourceName=<cs-resource-name>
    
    az cognitiveservices account create --resource-group $groupName --name $csResourceName --location $region --kind TextAnalytics --sku F0 --custom-domain $csResourceName
    

    Note

    --sku F0 creates a free tier Azure AI services resource. Each subscription is limited to a quota of one free-tier TextAnalytics resource. If you're already over the quota, use --sku S instead.

Configure .NET app

Clone the sample repository locally and deploy the sample application to App Service. Replace <app-name> with a unique name.

# Save app name as variable for convenience
appName=<app-name>

# Clone sample application
git clone https://github.com/Azure-Samples/app-service-language-detector.git
cd app-service-language-detector/dotnet

az webapp up --sku F1 --resource-group $groupName --name $appName --plan $appName --location $region

Configure secrets as app settings

  1. Configure the Azure AI services secrets as app settings CS_ACCOUNT_NAME and CS_ACCOUNT_KEY.

    # Get subscription key for Cognitive Services resource
    csKey1=$(az cognitiveservices account keys list --resource-group $groupName --name $csResourceName --query key1 --output tsv)
    
    az webapp config appsettings set --resource-group $groupName --name $appName --settings CS_ACCOUNT_NAME="$csResourceName" CS_ACCOUNT_KEY="$csKey1"
    
  2. In the browser, navigate to your deploy app at <app-name>.chinacloudsites.cn and try out the language detector with strings in various languages.

    Screenshot that shows deployed language detector app in App Service.

    If you look at the application code, you may notice the debug output for the detection results in the same font color as the background. You can see it by trying to highlight the white space directly below the result.

Secure back-end connectivity

At the moment, connection secrets are stored as app settings in your App Service app. This approach is already securing connection secrets from your application codebase. However, any contributor who can manage your app can also see the app settings. In this step, you move the connection secrets to a key vault, and lock down access so that only you can manage it and only the App Service app can read it using its managed identity.

  1. Create a key vault. Replace <vault-name> with a unique name.

    # Save app name as variable for convenience
    vaultName=<vault-name>
    
    az keyvault create --resource-group $groupName --name $vaultName --location $region --sku standard --enable-rbac-authorization
    

    The --enable-rbac-authorization parameter sets Azure role-based access control (RBAC) as the permission model. This setting by default invalidates all access policies permissions.

  2. Give yourself the Key Vault Secrets Officer RBAC role for the vault.

    vaultResourceId=$(az keyvault show --name $vaultName --query id --output tsv)
    myId=$(az ad signed-in-user show --query id --output tsv)
    az role assignment create --role "Key Vault Secrets Officer" --assignee-object-id $myId --assignee-principal-type User --scope $vaultResourceId
    
  3. Enable the system-assigned managed identity for your app, and give it the Key Vault Secrets User RBAC role for the vault.

    az webapp identity assign --resource-group $groupName --name $appName --scope $vaultResourceId --role  "Key Vault Secrets User"
    
  4. Add the Azure AI services resource name and subscription key as secrets to the vault, and save their IDs as environment variables for the next step.

    csResourceKVUri=$(az keyvault secret set --vault-name $vaultName --name csresource --value $csResourceName --query id --output tsv)
    csKeyKVUri=$(az keyvault secret set --vault-name $vaultName --name cskey --value $csKey1 --query id --output tsv)
    
  5. Previously, you set the secrets as app settings CS_ACCOUNT_NAME and CS_ACCOUNT_KEY in your app. Now, set them as key vault references instead.

    az webapp config appsettings set --resource-group $groupName --name $appName --settings CS_ACCOUNT_NAME="@Microsoft.KeyVault(SecretUri=$csResourceKVUri)" CS_ACCOUNT_KEY="@Microsoft.KeyVault(SecretUri=$csKeyKVUri)"
    
  6. In the browser, navigate to <app-name>.chinacloudsites.cn again. If you get detection results back, then you're connecting to the Azure AI services endpoint with key vault references.

Congratulations, your app is now connecting to Azure AI services using secrets kept in your key vault, without any changes to your application code.

Clean up resources

In the preceding steps, you created Azure resources in a resource group. If you don't expect to need these resources in the future, delete the resource group by running the following command in the local Shell:

az group delete --name $groupName

This command may take a minute to run.

Next steps