Service-to-service authentication to Azure Key Vault using .NET

To authenticate to Azure Key Vault you need an Azure Active Directory (AD) credential, either a shared secret or a certificate.

Managing such credentials can be difficult and it's tempting to bundle credentials into an app by including them in source or configuration files. The Microsoft.Azure.Services.AppAuthentication for .NET library simplifies this problem. It uses the developer's credentials to authenticate during local development. When the solution is later deployed to Azure, the library automatically switches to application credentials. Using developer credentials during local development is more secure because you do not need to create Azure AD credentials or share credentials between developers.

The Microsoft.Azure.Services.AppAuthentication library manages authentication automatically, which in turn allows you to focus on your solution, rather than your credentials. It supports local development with Microsoft Visual Studio, Azure CLI, or Azure AD Integrated Authentication. When deployed to an Azure resource that supports a managed identity, the library automatically uses managed identities for Azure resources. No code or configuration changes are required. The library also supports direct use of Azure AD client credentials when a managed identity is not available, or when the developer's security context cannot be determined during local development.

Using the library

For .NET applications, the simplest way to work with a managed identity is through the Microsoft.Azure.Services.AppAuthentication package. Here's how to get started:

  1. Add references to the Microsoft.Azure.Services.AppAuthentication and Microsoft.Azure.KeyVault NuGet packages to your application.

  2. Add the following code:

    using Microsoft.Azure.Services.AppAuthentication;
    using Microsoft.Azure.KeyVault;
    
    // Instantiate a new KeyVaultClient object, with an access token to Key Vault
    var azureServiceTokenProvider1 = new AzureServiceTokenProvider();
    var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider1.KeyVaultTokenCallback));
    
    // Optional: Request an access token to other Azure services
    var azureServiceTokenProvider2 = new AzureServiceTokenProvider();
    string accessToken = await azureServiceTokenProvider2.GetAccessTokenAsync("https://management.azure.com/").ConfigureAwait(false);
    

The AzureServiceTokenProvider class caches the token in memory and retrieves it from Azure AD just before expiration. Consequently, you no longer have to check the expiration before calling the GetAccessTokenAsync method. Just call the method when you want to use the token.

The GetAccessTokenAsync method requires a resource identifier. To learn more, see which Azure services support managed identities for Azure resources.

Local development authentication

For local development, there are two primary authentication scenarios: authenticating to Azure services, and authenticating to custom services.

Authenticating to Azure Services

Local machines do not support managed identities for Azure resources. As a result, the Microsoft.Azure.Services.AppAuthentication library uses your developer credentials to run in your local development environment. When the solution is deployed to Azure, the library uses a managed identity to switch to an OAuth 2.0 client credential grant flow. This means you can test the same code locally and remotely without worry.

For local development, AzureServiceTokenProvider fetches tokens using Visual Studio, Azure command-line interface (CLI), or Azure AD Integrated Authentication. Each option is tried sequentially and the library uses the first option that succeeds. If no option works, an AzureServiceTokenProviderException exception is thrown with detailed information.

Authenticating with Visual Studio

Authenticating with Visual Studio has the following prerequisites:

  1. Visual Studio 2017 v15.5 or later.

  2. The App Authentication extension for Visual Studio, available as a separate extension for Visual Studio 2017 Update 5 and bundled with the product in Update 6 and later. With Update 6 or later, you can verify the installation of the App Authentication extension by selecting Azure Development tools from within the Visual Studio installer.

Sign in to Visual Studio and use Tools > Options > Azure Service Authentication to select an account for local development.

If you run into problems using Visual Studio, such as errors regarding the token provider file, carefully review these steps.

It may also be necessary to reauthenticate your developer token. To do so, go to Tools > Options>Azure Service Authentication and look for a Re-authenticate link under the selected account. Select it to authenticate.

Authenticating with Azure CLI

To use Azure CLI for local development:

  1. Install Azure CLI v2.0.12 or later. Upgrade earlier versions.

  2. Use az login to sign in to Azure.

Use az account get-access-token to verify access. If you receive an error, verify that Step 1 completed successfully.

If Azure CLI is not installed to the default directory, you may receive an error reporting that AzureServiceTokenProvider cannot find the path for Azure CLI. Use the AzureCLIPath environment variable to define the Azure CLI installation folder. AzureServiceTokenProvider adds the directory specified in the AzureCLIPath environment variable to the Path environment variable when necessary.

If you are signed in to Azure CLI using multiple accounts or your account has access to multiple subscriptions, you need to specify the specific subscription to be used. To do so, use:

az account set --subscription <subscription-id>

This command generates output only on failure. To verify the current account settings, use:

az account list

Authenticating with Azure AD authentication

To use Azure AD authentication, verify that:

  • Your on-premises active directory syncs to Azure AD.

  • Your code is running on a domain-joined machine.

Authenticating to custom services

When a service calls Azure services, the previous steps work because Azure services allow access to both users and applications.

When creating a service that calls a custom service, use Azure AD client credentials for local development authentication. There are two options:

  1. Use a service principal to sign into Azure:

    1. Create a service principal.

    2. Use Azure CLI to sign in:

      az login --service-principal -u <principal-id> --password <password> --tenant <tenant-id> --allow-no-subscriptions
      

      Because the service principal may not have access to a subscription, use the --allow-no-subscriptions argument.

  2. Use environment variables to specify service principal details. For details, see Running the application using a service principal.

Once you've signed in to Azure, AzureServiceTokenProvider uses the service principal to retrieve a token for local development.

This applies only to local development. When your solution is deployed to Azure, the library switches to a managed identity for authentication.

Running the application using managed identity or user-assigned identity

When you run your code on an Azure App Service or an Azure VM with a managed identity enabled, the library automatically uses the managed identity. No code changes are required, but the managed identity must have get permissions for the key vault. You can give the managed identity get permissions through the key vault's Access Policies.

Alternatively, you may authenticate with a user-assigned identity. For more information on user-assigned identities, see About Managed Identities for Azure resources. To authenticate with a user-assigned identity, you need to specify the Client ID of the user-assigned identity in the connection string. The connection string is specified in the Connection String Support section below.

Running the application using a Service Principal

It may be necessary to create an Azure AD Client credential to authenticate. Common examples include:

  • Your code runs on a local development environment, but not under the developer's identity. Service Fabric, for example, uses the NetworkService account for local development.

  • Your code runs on a local development environment and you authenticate to a custom service, so you can't use your developer identity.

  • Your code is running on an Azure compute resource that does not yet support managed identities for Azure resources, such as Azure Batch.

There are three primary methods of using a Service Principal to run your application. To use any of them, you must first create a service principal.

Use a certificate in local keystore to sign into Azure AD

  1. Create a service principal certificate using the Azure CLI az ad sp create-for-rbac command.

    az ad sp create-for-rbac --create-cert
    

    This will create a .pem file (private key) that will be stored in your home directory. Deploy this certificate to either the LocalMachine or CurrentUser store.

    Important

    The CLI command generates a .pem file, but Windows only provides native support for PFX certificates. To generate a PFX certificate instead, use the PowerShell commands shown here: Create service principal with self-signed certificate. These commands automatically deploy the certificate as well.

  2. Set an environment variable named AzureServicesAuthConnectionString to:

    RunAs=App;AppId={AppId};TenantId={TenantId};CertificateThumbprint={Thumbprint};
          CertificateStoreLocation={CertificateStore}
    

    Replace {AppId}, {TenantId}, and {Thumbprint} with values generated in Step 1. Replace {CertificateStore} with either LocalMachine or CurrentUser, based on your deployment plan.

  3. Run the application.

Use a shared secret credential to sign into Azure AD

  1. Create a service principal certificate with a password using az ad sp create-for-rbac --password.

  2. Set an environment variable named AzureServicesAuthConnectionString to:

    RunAs=App;AppId={AppId};TenantId={TenantId};AppKey={ClientSecret} 
    

    Replace {AppId}, {TenantId}, and {ClientSecret} with values generated in Step 1.

  3. Run the application.

Once everything's set up correctly, no further code changes are necessary. AzureServiceTokenProvider uses the environment variable and the certificate to authenticate to Azure AD.

Use a certificate in Key Vault to sign into Azure AD

This option allows you to store a service principal's client certificate in Key Vault and use it for service principal authentication. You may use this for the following scenarios:

  • Local authentication, where you want to authenticate using an explicit service principal, and want to keep the service principal credential securely in a key vault. Developer account must have access to the key vault.
  • Authentication from Azure where you want to use explicit credential (e.g. for cross-tenant scenarios), and want to keep the service principal credential securely in a key vault. Managed identity must have access to key vault.

The managed identity or your developer identity must have permission to retrieve the client certificate from the Key Vault. The AppAuthentication library uses the retrieved certificate as the service principal's client credential.

To use a client certificate for service principal authentication

  1. Create a service principal certificate and automatically store it in your keyvault using the Azure CLI az ad sp create-for-rbac --keyvault --cert --create-cert --skip-assignment command:

    az ad sp create-for-rbac --keyvault <keyvaultname> --cert <certificatename> --create-cert --skip-assignment
    

    The certificate identifier will be a URL in the format https://<keyvaultname>.vault.azure.net/secrets/<certificatename>

  2. Replace {KeyVaultCertificateSecretIdentifier} in this connection string with the certificate identifier:

    RunAs=App;AppId={TestAppId};KeyVaultCertificateSecretIdentifier={KeyVaultCertificateSecretIdentifier}
    

    If, for instance your key vault was called "myKeyVault" and you created a certificate called 'myCert', the certificate identifier would be:

    RunAs=App;AppId={TestAppId};KeyVaultCertificateSecretIdentifier=https://myKeyVault.vault.azure.net/secrets/myCert
    

Connection String Support

By default, AzureServiceTokenProvider uses multiple methods to retrieve a token.

To control the process, use a connection string passed to the AzureServiceTokenProvider constructor or specified in the AzureServicesAuthConnectionString environment variable.

The following options are supported:

Connection string option Scenario Comments
RunAs=Developer; DeveloperTool=AzureCli Local development AzureServiceTokenProvider uses AzureCli to get token.
RunAs=Developer; DeveloperTool=VisualStudio Local development AzureServiceTokenProvider uses Visual Studio to get token.
RunAs=CurrentUser Local development AzureServiceTokenProvider uses Azure AD Integrated Authentication to get token.
RunAs=App Managed identities for Azure resources AzureServiceTokenProvider uses a managed identity to get token.
RunAs=App;AppId={ClientId of user-assigned identity} User-assigned identity for Azure resources AzureServiceTokenProvider uses a user-assigned identity to get token.
RunAs=App;AppId={TestAppId};KeyVaultCertificateSecretIdentifier={KeyVaultCertificateSecretIdentifier} Custom services authentication KeyVaultCertificateSecretIdentifier = the certificate's secret identifier.
RunAs=App;AppId={AppId};TenantId={TenantId};CertificateThumbprint={Thumbprint};CertificateStoreLocation={LocalMachine or CurrentUser} Service principal AzureServiceTokenProvider uses certificate to get token from Azure AD.
RunAs=App;AppId={AppId};TenantId={TenantId};CertificateSubjectName={Subject};CertificateStoreLocation={LocalMachine or CurrentUser} Service principal AzureServiceTokenProvider uses certificate to get token from Azure AD
RunAs=App;AppId={AppId};TenantId={TenantId};AppKey={ClientSecret} Service principal AzureServiceTokenProvider uses secret to get token from Azure AD.

Samples

To see the Microsoft.Azure.Services.AppAuthentication library in action, please refer to the following code samples.

  1. Use a managed identity to retrieve a secret from Azure Key Vault at runtime

  2. Programmatically deploy an Azure Resource Manager template from an Azure VM with a managed identity.

  3. Use .NET Core sample and a managed identity to call Azure services from an Azure Linux VM.

AppAuthentication Troubleshooting

Common issues during local development

Azure CLI is not installed, you are not logged in, or you do not have the latest version

Run az account get-access-token to see if Azure CLI shows a token for you. If it says no such program found, please install the latest version of the Azure CLI. If you have installed it, you may be prompted to login.

AzureServiceTokenProvider cannot find the path for Azure CLI

AzureServiceTokenProvider looks for Azure CLI at its default install locations. If it cannot find Azure CLI, please set environment variable AzureCLIPath to the Azure CLI installation folder. AzureServiceTokenProvider will add the environment variable to the Path environment variable.

You are logged into Azure CLI using multiple accounts, the same account has access to subscriptions in multiple tenants, or you get an Access Denied error when trying to make calls during local development

Using Azure CLI, set the default subscription to one which has the account you want use, and is in the same tenant as the resource you want to access: az account set --subscription [subscription-id]. If no output is seen, then it succeeded. Verify the right account is now the default using az account list.

Common issues across environments

Unauthorized access, access denied, forbidden, etc. error

The principal used does not have access to the resource it is trying to access. Grant either your user account or the App Service's MSI "Contributor" access to the desired resource, depending on whether you are running the sample on your local development machine or deployed in Azure to your App Service. Some resources, like key vaults, also have their own access policies that you use grant access to principals (users, apps, groups, etc.).

Common issues when deployed to Azure App Service

Managed identity is not setup on the App Service

Check the environment variables MSI_ENDPOINT and MSI_SECRET exist using Kudu debug console. If these environment variables do not exist, Managed Identity is not enabled on the App Service.

Common issues when deployed locally with IIS

Can't retrieve tokens when debugging app in IIS

By default, AppAuth runs in a different user context in IIS and therefore does not have access to use your developer identity to retrieve access tokens. You can configure IIS to run with your user context with the following two steps:

  • Configure the Application Pool for the web app to run as your current user account. See more information here

  • Configure "setProfileEnvironment" to "True". See more information here.

    • Go to %windir%\System32\inetsrv\config\applicationHost.config
    • Search for "setProfileEnvironment". If it is set to "False", change it to "True". If it is not present, add it as an attribute to the processModel element (/configuration/system.applicationHost/applicationPools/applicationPoolDefaults/processModel/@setProfileEnvironment), and set it to "True".
  • Learn more about managed identities for Azure resources.

  • Learn more about Azure AD authentication scenarios.