Managed Identity is an awesome feature in Azure which allows your Azure applications and services to communicate securely without handling or maintaining any credentials to do so. It is a very simple service to use and work with. But how can a Virtual Machine or App Service identify itself and be allowed access to other services? That is what we will be looking into in this post. First, let's quickly go over why we should be using Managed Identity and what it really is.
Using Managed Identity means that there is no risk of accidentally committing secrets into git, no secrets that are shared over email etc. Added to that, the task of maintaining and regenerating credentials is all handled by Azure behind the scenes. The lifetime of the Managed Identity is the same as the resource, so if the resource is removed, so is the Identity, meaning there is no additional clean up necessary. It also doesn't matter what language you are writing your code in, the requirement is that your application is running on an Azure Service which supports Managed Identity. All these benefits really means that we let Azure manage the maintenance and security parts for us, which they are happy to do, and we as developers can focus on what it is that we do best.
Now that we know why we should be using Managed Identity, what is it really? In order to explain it, let us first take a look at the context of it all. Managed Identity is really a feature inside Azure Active Directory (AAD), and it's place inside the AAD is shown below in the picture. Note that this picture only shows a very limited part of the Identity part of the AAD, but it helps to put it into context.
Simply put, Managed Identity is a Service Principal, much similar to an App Registration, but instead maintained completely by Azure behind the scenes. Meaning it has the same basic functionality, but less customizable. What happens when we enable Managed Identity on a service is that a Service Principal is created in our AAD, which we then give access to other services, in the same way we would give any User Principal or Service Principal access, as shown below.
Once we have enabled Managed Identity on our service, a Function App in this case, we can give it access to another resource, for instance a Key Vault like below.
Now that the service has MI enabled, you can retrieve an access token to use towards different resources. How to retrieve this token is usually based on what language you are using and what tools are available. As a .NET developer for instance, I would use the AppAuthentication NuGet provided by Microsoft, and these lines would pretty much be enough.
using Microsoft.Azure.Services.AppAuthentication;
...
...
var resource = "https://database.windows.net/";
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var accessToken = await azureServiceTokenProvider.GetAccessTokenAsync(resource);
In the example above, resource is the resource that you are trying to access. To find all the services supporting Managed Identity, and what resources to specify, look at the official documentation provided by Microsoft here as support for Managed Identity is frequently being added.
This is kind of all you need to know in order to use Managed Identity in a good and effective way. However, the scope of this blog post is to look behind the scenes of it all in order to understand it.
What is happening on the resources is different depending on the type of resource. Let us look at what is happening for App Services (I.e. Web, API and Function Apps) and Virtual Machines.
App Services
On the App Services, when you enable Managed Identity, a local endpoint is set up, and this endpoint and a secret is added to the App Service environmental variables. You can check this by going into the App Service using Kudu and looking at the environment variables, there are now 4 new variables.
The endpoint is only reachable from this app service, and the port used and the secret is regenerated and updated regularly, multiple times a day. With these settings, it is now possible to retrieve a token that is valid for the resource we are trying to access. If we use the console inside Kudu, we can simply make a HTTP request using CURL to the endpoint provided, attaching a X-IDENTITY-HEADER to the request, and specifying the resource we want to access.
curl -H "X-IDENTITY-HEADER: {secret}" "{endpoint}?resource={resource}&api-version=2019-08-01"
In this case, for my App Service to retrieve a token which is valid for an Azure Managed Database, the request could look like this:
curl -H "X-IDENTITY-HEADER: 4B739BBFDF5D43E48BAE2E79515314B2" "http://127.0.0.1:41570/MSI/token/?resource=https://database.windows.net/&api-version=2019-08-01"
Virtual Machines
For Virtual Machines, The idea is the same, but the details differ slightly. Azure VMs have access to an endpoint called Azure Instance Metadata service (IMDS). This is also an endpoint that is only accessible from the VM in question, where it is possible to retrieve a bunch of metadata about this particular VM. When enabling Managed Identity on this VM, a Service Principal is again created in the AAD, and the Client Id and Certificate of that Service Principal is added to this IMDS. So when the Virtual Machine wants to retrieve an access token using Managed Identity, it makes a HTTP call to the IMDS endpoint (which is always at http://169.254.169.254/) instead.
curl -H "Metadata:true" "http://169.254.169.254/metadata/identity/oauth2/token??resource=https://database.windows.net/&api-version=2018-02-01"
A more detailed picture as to how the entire flow works is shown below.
In conclusion, Managed Identity works very similar as a regular App Registration, it simply adds the Secret/Certificate behind the scenes where it is only available to the service itself.
Simply put, Managed Identity is a Service Principal which Azure have abstracted to the point where it is really simple to use and nothing to manage, so that you as a developer can focus on the important things and bring value to the business.
Top comments (3)
The Microsoft.Azure.Services.AppAuthentication is deprecated. Can you please update the content using latest Azure.Identity package? I am using Entity framework core in .net 6 web api proj. I want to connect to Azure sql using AD managed identity.
Great post! I'd love to see a follow up post that explains how it works on other Azure services such as Azure Data Factory.
Thanks for sharing this valuable information.