Accessing APIs using Azure Managed Service Identity
By: Vidar Kongsli
Tags: Azure Ad, Identity, Microsoft, Aspnetcore, Azure

In the post Protecting your ASP.NET Core app with Azure AD and managed service identity, I showed how to access an Azure Key Vault and Azure SQL databases using Azure Managed Service Identity. In this post, we take this a step further to access other APIs protected by Azure AD, like Microsoft Graph and Azure Active Directory Graph API.

After acquiring an access token from AAD, it can be used as a bearer token in requests to Azure SQL, keyvault and Microsoft Graph API.

A brief on access permissions

Before moving on, let’s take a minute to talk about permissions. In the context of Azure Active Directory there are two types of permissions given to applications:

Application permissions — are permissions given to the application itself. In this scenario, the resource given access to does not have any knowledge of the permissions of the end user. In earlier literature from Microsoft patterns and practices, this model is also referred to as the “trusted subsystem” model where the idea is that the API resource trust the caller system to do the proper authorization of end users. For example, for web applications this has “always” been the model used for calling an SQL server.

— are permissions given to the application itself. In this scenario, the resource given access to does not have any knowledge of the permissions of the end user. In earlier literature from Microsoft patterns and practices, this model is also referred to as the “trusted subsystem” model where the idea is that the API resource trust the caller system to do the proper authorization of end users. For example, for web applications this has “always” been the model used for calling an SQL server. Delegated permissions — are permissions that the end-user delegates to the application for access to the user’s data/resources. For instance, the application can be given access to the end user’s mailbox. This is analogue to what in earlier literature is referred to as “impersonation”, meaning that the application impersonates the end user when calling the API resource. The application acts on behalf of the end user, for instance a third party application might post on your Twitter timeline.

In this post, we talk about application permissions only.

Granting the application access to the API

Now that the have made a brief introduction to permissions, it’s time to grant the application, via its service principal, access to the API. Let’s use the Microsoft Graph API as an example. This operation cannot (at the time of writing) be done in the Azure Portal, so we have to turn to the AzureAD PowerShell module for this.

Connecting to Azure AD

If you haven’t already, the first step is to install the module:

Install-Module AzureAD

And then initiate a session with Azure AD:

Connect-AzureAD

Finding service principals

The next thing we need to do is to find the service principal for the application. If you need an explanation of the service principal concept, you can find a very good one here. We can find the service principal by the application’s displayName (here, we assume that $webSiteName refers to the name we gave when provisioning the web app using ARM templates in my previous blog post):

$webSiteServicePrincipal = Get-AzureADServicePrincipal -Filter "displayName eq '$webSiteName'"

What we need next is the service principal for the Microsoft Graph API. For that, we can use the application ID for the Graph API, which is 00000003-0000-0000-c000-000000000000 (for Microsoft’s APIs, you can look this up in the docs. If you want to give access to a custom API that you or a third party has created, you need to use the application id assigned to that application). We can then do a search like this:

$GraphServicePrincipal = Get-AzureADServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'"

Finding application role

We have the service principals for both the API and the application, and we need to find what permission or permissions we want to give to the application. We can find the available permissions for the Microsoft Graph API here. Let’s say we want to give the application the Directory.Read.All permission.

What we need to do, is to find the application role that gives this permission:

$AppRole = $GraphServicePrincipal.AppRoles | Where-Object {$_.Value -eq 'Directory.Read.All' -and $_.AllowedMemberTypes -contains 'Application'}

In the snippet above, we search through the list of application role for the API service principal and select the application permission with the permission Directory.Read.All.

Granting access

We now have all that we need to issue the command to grant the permission:

New-AzureAdServiceAppRoleAssignment `

-ObjectId $webSiteServicePrincipal.ObjectId `

-PrincipalId $webSiteServicePrincipal.ObjectId `

-ResourceId $GraphServicePrincipal.ObjectId `

-Id $AppRole.Id

That is basically what is required. However, it is important to note that this command might return an error in some circumstances, for instance if the application has already been assigned this role. So, to be sure that everything is OK, we can query Azure AD to check that the application role has been successfully assigned:

Get-AzureADServiceAppRoleAssignment `

-ObjectId $GraphServicePrincipal.ObjectId `

| Where-Object { $_.Id -eq $AppRole.Id -and $_.PrincipalId -eq

$webSiteServicePrincipal.ObjectId }

Calling Microsoft Graph from ASP.NET Core

Since the managed identity is in place, and the permissions have been granted, we can now call the Microsoft Graph from our ASP.NET Core application.

There are two essential Nuget packages that we will use:

Install-Package Microsoft.Azure.Services.AppAuthentication

Install-Package Microsoft.Graph

Let’s create a factory that will instantiate a graph API client and acquire an access token for it:

And then register it for dependency injection:

Finally, we can call the graph API from a controller (for instance):

Summary

We have now added the possibility to connect to Microsoft Graph API from our application using the managed service identity. In all, the application can connect to an Azure Key vault, Azure SQL server and to Azure AD-protected APIs. This can easily be extended to granting access to custom applications protected by Azure AD.

The code for the sample application as well as the PowerShell script for granting permission can be found in this GitHub repository.