OdeToCode IC Logo

Key Vault and Managed Service Identities

Wednesday, June 13, 2018

In previous posts we look at decryption with Azure Key Vault and how to think about the roles of the people and services interacting with Key Vault. In this post I want to call attention to an Azure feature that you can use in combination with Key Vault – the Managed Service Identity (MSI).

MSI helps to solve the Key Vault bootstrapping problem whereby an application needs access to a configuration secret stored outside of Key Vault to access all the secrets inside of Key Vault.

First, here’s the Startup code from the earlier post about decryption. This code needs an application ID and an application secret to access Key Vault.

AuthenticationCallback callback = async (authority,resource,scope) =>
{
    var appId = Configuration["AppId"];
    var appSecret = Configuration["AppSecret"];

    var authContext = new AuthenticationContext(authority);
    var credential = new ClientCredential(appId, appSecret);
    var authResult = await authContext.AcquireTokenAsync(resource, credential);
    return authResult.AccessToken;
};

var client = new KeyVaultClient(callback);

If this code is running in an environment where Azure Managed Service Identity is available, we could enable MSI, install the Microsoft.Azure.Services.AppAuthentication NuGet package, and then replace the code from above with the following.

var tokenProvider = new AzureServiceTokenProvider();
var callback = new AuthenticationCallback(tokenProvider.KeyVaultTokenCallback);
return new KeyVaultClient(callback);

Not only is the code simpler, but we don’t need to explicitly create and manage an application secret that gives the application access to Key Vault. People who talk to me about Key Vault worry about this secret because this is the secret that grants access to all other secrets. With MSI, the master secret isn’t explicitly required by the application. However, a secret is still in play. MSI makes the secret safer and easier to use.

What is MSI?

MSI is a feature of Azure AD available to specific types of services in Azure, including VMs, App Services, and Functions. When you create one of these services you have the option to enable MSI in the portal or with the command line. For an App Service I can enable MSI using:

az webapp assign-identity –resource-group {group} –name {name}
This command will create a managed identity for my app service. If the app service goes away, the managed identity goes away. Azure also takes care of rolling the credentials.

Enable MSI in the Portal

Enabling MSI for a resource also enables a local token endpoint for the resource. In an app service, this endpoint looks like http://127.0.0.1:41068/MSI/token/. This endpoint is where the AzureServiceTokenProvider can go to pick up a token. All the provider needs is a secret. For App Services, both the endpoint and the secret are available as environment variables.

Environment variableds as listerd in Project Kudu

The Magic of the AzureServiceTokenProvider

I like to see how software fails, so I had to run the app using an AzureServiceTokenProvider on my local laptop - far away from MSI environment variables and token endpoints.

To my surprise, the application was able to read a secret in Key Vault.

It turns out that AzureServiceTokenProvider has more than one strategy for obtaining a bearer token. One approach is to use the local MSI endpoint provided by Azure when running in Azure, but another approach is to use the Azure CLI. If you are logged in with the Azure CLI, the token provider can use the equivalent of the following to obtain an access token.

az account get-access-token
A different token provider can obtain a token via Visual Studio.

Summary

More and more services in Azure can now use Azure AD authentication, including Service Bus and as of May, Azure Storage. Using MSI in combination with the AzureServiceTokenProvider makes Azure AD authentication easier and safer.


Comments
Gravatar Mallikh Wednesday, June 13, 2018
Hi Scott, I have a question and i am sure this would be a dumb question but i still want to go ahead and ask. You said : Enabling MSI for a resource also enables a local token endpoint for the resource. In an app service, this endpoint looks like http://127.0.0.1:41068/MSI/token/. doesn't it mean that this end point is accessible for every one without even they being authenticated?
Gravatar Matthew Steeples Thursday, June 14, 2018
It does mean that, but if someone else is running code on your server then you potentially have bigger problems! The endpoint is only accessible from the local computer. Does that answer your question? Happy to clarify if not.
Gravatar Paul Schaeflein Thursday, June 14, 2018
The localhost address is moving to a new Azure Instance Metadata Service (IMDS) identity endpoint. More details here: https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview More details about using the Microsoft.Azure.Services.AppAuthentication library here: https://docs.microsoft.com/en-us/azure/key-vault/service-to-service-authentication
Gravatar Mallikh Thursday, June 14, 2018
Thanks for the explanation @Matthew. In the Azure scenario if i am using the app service plan in a free tier will there be a possibility of some one else being able to access this local URL? I am assuming NO as all the app services have their own boundaries and also you cannot login to the virtual machine? I am asking this because in free tier app services will be sharing web servers.
Gravatar Scott Monday, June 18, 2018
Keep in mind the endpoint is dynamic and the environment variables for the endpoint and the secret can be set for a specific process.
Your Comment