Jul 152019
 

On a recent support case a customer wished to assign Azure AD Graph API permissions to his Managed Service Identity (MSI). If this was a standard Application Registration, assigning API permissions is quite easy from the portal by following the steps outlined in Azure AD API Permissions. However, today Managed Service Identities are not represented by an Azure AD app registration so granting API permissions is not possible in the Azure AD portal for MSIs.

Luckily, this is possible with the Azure AD and Azure PowerShell modules as well as Azure CLI shown via my colleague Liam Smith’s code samples below:

Assigning via PowerShell

#First define your environment variables
$TenantID="91ceb514-5ead-468c-a6ae-048e103d57f0"
$subscriptionID="ed6a63cc-c71c-4bfa-8bf7-c1510b559c72"
$DisplayNameOfMSI="AADDS-Client03"
$ResourceGroup="AADDS"
$VMResourceGroup="AADDS"
$VM="AADDS-Client03"

#If your User Assigned Identity doesnt exist yet, create it now
New-AzUserAssignedIdentity -ResourceGroupName $ResourceGroup -Name $DisplayNameOfMSI

#Now use the AzureAD Powershell module to grant the role
Connect-AzureAD -TenantId $TenantID #Connected as GA
$MSI = (Get-AzureADServicePrincipal -Filter "displayName eq '$DisplayNameOfMSI'")
Start-Sleep -Seconds 10
$GraphAppId = "00000002-0000-0000-c000-000000000000" #Windows Azure Active Directory
$GraphServicePrincipal = Get-AzureADServicePrincipal -Filter "appId eq '$GraphAppId'"
$PermissionName = "Directory.Read.All"
$AppRole = $GraphServicePrincipal.AppRoles | Where-Object {$_.Value -eq $PermissionName -and $_.AllowedMemberTypes -contains "Application"}
New-AzureAdServiceAppRoleAssignment -ObjectId $MSI.ObjectId -PrincipalId $MSI.ObjectId -ResourceId $GraphServicePrincipal.ObjectId -Id $AppRole.Id  

#NOTE: The above assignment may indicate bad request or indicate failure but it has been noted that the permission assignment still succeeds and you can verify with the following command
Get-AzureADServiceAppRoleAssignment -ObjectId $GraphServicePrincipal.ObjectId | Where-Object {$_.PrincipalDisplayName -eq $DisplayNameOfMSI} | fl

At this point you should have been able to verify that your identity’s service principal has the correct app roles as shown below.

Get-AzureADServiceAppRoleAssignment showing that MSI principal has assigned AppRoleAssignment

You can now perform some tests to verify permissions via the following code on your Azure Virtual Machine that has the service identity assigned to it:

# First grab a bearer token for Azure AD Graph API using IMDS endpoint on Azure VM
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.windows.net' -Method GET -Headers @{Metadata="true"}
$content = $response.Content | ConvertFrom-Json 
$token = $content.access_token 

You can copy\paste the value of $token to https://jwt.io to verify that your token is showing the Directory.Read.All permission properly.

Output of pasting $token contents to https://jwt.io to verify Directory.Read.All role

If for some reason your $token does not show the Directory.Read.All permission, try rebooting your Azure Virtual Machine as it is possible a previous failed request for a bearer token was cached on your VM

Now, continue testing on your Azure VM by using this $token to make a call to Azure AD Graph API :

$output = (Invoke-WebRequest -Uri "https://graph.windows.net/myorganization/users?api-version=1.6" -Method GET -Headers @{Authorization="Bearer $token"}).content
$json = ConvertFrom-Json $output
$json.value

Your $json.value output should be the successful response of your Azure AD Graph API call. Hope this helps someone!

Assigning via Azure CLI

You can also perform the same steps using Azure CLI and CURL if this is your preferred management environment. See below for Liam’s steps via Azure CLI

1) Get accesstoken:
az account get-access-token --resource "https://graph.windows.net/"

2) Assign accessToken to variable
accessToken=<your access token>

3) Confirm access to graph.windows.net:
curl 'https://graph.windows.net/mytenant.onmicrosoft.com/users?api-version=1.6' -H "Authorization: Bearer $accessToken"

4) Assign object ID of service principal to variable objectID
objectID=<object ID>

5) Give permissions of 'Directory.Read.All' to the service prinicpal:
curl "https://graph.windows.net/mytenantonmicrosoft.com/servicePrincipals/$objectID/appRoleAssignments?api-version=1.6" -X POST -d '{"id":"5778995a-e1bf-45b8-affa-663a9f3f4d04","principalId":"$objectID","resourceId":"5e20606e-f80c-4695-9147-97a1fb962853"}' -H "Content-Type: application/json" -H "Authorization: Bearer $accessToken"

6) Test on VM:
curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&amp;resource=https://graph.windows.net' -H Metadata:true
accessToken=<accessToken>
curl 'https://graph.windows.net/mytenant.onmicrosoft.com/users?api-version=1.6' -H "Authorization: Bearer $accessToken"

  3 Responses to “Assigning Azure AD Graph API Permissions to a Managed Service Identity (MSI)”

  1. Hi Jason,

    Nice description how to give a MSI API Permissions. Thanks for that, it is exactly what I was looking for. 🙂

    Unfortunately it does not work completely for me. Even tough I can assign the app role to the manged identity the access token never has the ‘Directory.Read.All’ role included. Therefore I can still not access the Azure AD Graph API. Did I missing something?

    Do I have to to do somehow the admin consent after the role was assigned to the managed identity? (like pressing the “Grant admin consent” button when it is done in the Portal for a normal App Registration) Or is this not needed when I run the command under an account with Global Admin permissions?

    Thx
    Jonas

    • When you get your access token, are you checking it via a site such as jwt.ms or jwt.io? Have you tried rebooting your VM or resource to make sure you are not using a cached MSI cert\token? That has been the fix for most people after successfully assigning permissions.

      • Yes I was checking the token on jwt.io and it works as you have described and the reboot has fixed it for me also. But for me was the trick to fully stop/deallocate and start the VM again. Just rebooting trough the OS or the Portal had no effect.

        Thx
        Jonas

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)