When running an app in Azure App Service and using Managed Identities to connect to services, sometimes you can run into issues. A service like Key Vault might be returning a 403 Forbidden error, but you are not sure why. I've found it often helps to check what the access token contains to ensure the necessary permissions etc. are there. You could also test the request that the app is trying to run by using the token.

To acquire a Managed Identity access token, we need to call an HTTP endpoint from within the App Service. We can do that through Kudu, aka Advanced Tools from the App Service blade. Kudu is available to you if you have Write access to the App Service (for example through Contributor role). Barry Luijbregts summarized what Kudu is quite nicely in his article on Azure App Service:

The advanced tools feature takes you to the Kudu environment. This is a management web application, that runs next to your App Service App. In the Kudu environment, you can manage the filesystem, manage App Service extensions, see the processes that are running and more. Most of the features that made the Kudu environment unique in the past, are now elevated to first-class App Service features, like the console feature.

After opening Kudu, click Debug console, and then PowerShell. Then you can use a script like this to get an access token:

$resource = "https://graph.microsoft.com"

$endpoint = $env:IDENTITY_ENDPOINT
$header = $env:IDENTITY_HEADER
$apiVersion = "2019-08-01"

$headers = @{ 'X-Identity-Header' = $header }

$url = "$($endpoint)?api-version=$apiVersion&resource=$resource"

$response = Invoke-RestMethod -Method Get -Uri $url -Headers $headers
$response.access_token

This script gets an access token for Microsoft Graph API for the system-assigned Managed Identity. If you want an access token for a different API, change the $resource variable. You can find resource IDs for Azure services in the docs. If you are calling one of your APIs, you can use the App ID URI or client ID from its app registration.

To get an access token for a user-assigned Managed Identity, you need to add one more header to the request that identifies which identity to use. You can either send the client id, object id, or the Azure resource id of the identity. The options are in full detail in the docs.

Hopefully this helps someone!

Some thoughts on security

Now since Managed Identity allows you to call an API as an application, having the ability to get access tokens like this has some risks. If someone were to get access to the Kudu console, they would be able to call those APIs as the application. So they can then call APIs that the application has been authorized to call, and logs in the API will show the caller being the application, not the user.

You can protect against this by limiting write access to the App Service. If a user does not have e.g. Contributor role on the App Service, they cannot access Kudu. For this reason, you should audit who has this kind of roles on the app in production. If you have Azure AD Premium P2 licenses, you can use Privileged Identity Management to allow users to elevate to those roles on-demand with approval.

The issue here is of course not limited to getting access tokens as the app. Through Kudu you can for example edit files, so you could modify the code running there.

Links