While listening to the Secretless Apps with Christos Matskas episode on the M365 Developer Podcast it reminded me that still a lot of developers have no clue about Managed Identities and their advantages. Additionally, there were some unanswered questions in that episode that I could answer in a couple of blog posts. Thus a new series is born!
Now that you know about Managed Identities and you are convinced to use them, you need to assign permissions to them so they can access other Azure resources and APIs. The approach is different for both of them, so let's get going!
Managed identities are integrated into the UI of the Azure Portal, and giving a Managed Identity permissions on another Azure resource is no different from giving permissions to a User.
Assume you'd like to give this Managed Identity a certain type of permissions (Contribute) on a Resource Group. You go into that Resource Group -> Access control -> Role assignments:
You select +Add -> Role assignment, and in the newly opened side panel you select the Contributor role and start typing the name of the Managed Identity:
With User Assigned Managed Identities, you can even change the second dropdown Assign access to to User assigned managed identity and they show up automagically for you to select:
Don't forget to select Save, and you are done: your Managed Identity now has permissions on this Resource Group (and the best thing: this works with a lot of Azure resources just like that)!
APIs and other Azure AD registered applications
Assigning permissions to Azure AD registered applications and APIs is a lot harder, unfortunately. Managed Identities don't have this nice UI experience that you get when you have an App Registration where you can indicate that your app would like permissions to some particular Microsoft Graph scopes:
A Managed Identity is nothing more than a Service Principal and only shows up below Enterprise Applications, and not under App Registrations:
Within Enterprise Applications, you cannot adjust the permissions that this Service Principal needs as this UI is read-only:
There surely are many ways to achieve this, like Azure CLI or the Azure AD PowerShell module, but I decided to use the Microsoft Graph PowerShell module!
I had good reasons for choosing this over the others:
- It is cross-platform and works on .NET Core (which Azure AD PowerShell does not)
- I love Microsoft Graph 🧡
- I didn't have a use case before, so I never got to try out Microsoft Graph PowerShell and felt like this was a good time 😅
The script can be found in my GitHub repo msgraph-utility-scripts, or with a direct link. It requires you to have the Microsoft Graph PowerShell module installed, and you should have opened a connection with
Connect-MgGraph with the appropriate scopes as defined in:
- Get servicePrincipal
- List appRoleAssignments granted to a service principal
- Grant an appRoleAssignment to a service principal
The script allows to assign Application Permission scopes defined by an API Service Principal to a Service Principal, eg. assign
Team.Create defined by Microsoft Graph to your Managed Identity.
It allows to input the API Service Principal and the Service Principal by Application ID, by Display Name, or one by ID and the other by Display Name. It's flexible that way 😉. The scopes to be assigned are an array of all necessary scopes.
For known APIs (currently this means Microsoft Graph and SharePoint), the API Service Principal ID can be replaced by using the
-API MicrosoftGraph or
-API SharePoint switch.
Add-ApplicationPermissionsToServicePrincipal -ServicePrincipalAppId <String> -ApiServicePrincipalAppDisplayName <String> -ApplicationPermissionScopes <String> Add-ApplicationPermissionsToServicePrincipal -ServicePrincipalAppId <String> -ApiServicePrincipalAppId <String> -ApplicationPermissionScopes <String> Add-ApplicationPermissionsToServicePrincipal -ServicePrincipalAppId <String> -Api <Object> -ApplicationPermissionScopes <String> Add-ApplicationPermissionsToServicePrincipal -ServicePrincipalAppDisplayName <String> -ApiServicePrincipalAppDisplayName <String> -ApplicationPermissionScopes <String> Add-ApplicationPermissionsToServicePrincipal -ServicePrincipalAppDisplayName <String> -ApiServicePrincipalAppId <String> -ApplicationPermissionScopes <String> Add-ApplicationPermissionsToServicePrincipal -ServicePrincipalAppDisplayName <String> -Api <Object> -ApplicationPermissionScopes <String>
-ServicePrincipalAppId <String> Application Id of the Service Principal to which you are assigning the application permission(s) -ServicePrincipalAppDisplayName <String> Display name of the Service Principal to which you are assigning the application permission(s) -Api <Object> Predefined Service Principals for which application permission(s) can be assigned. When selecting one of these, ApiServicePrincipalAppId and ApiServicePrincipalDisplayName aren't used. -ApiServicePrincipalAppId <String> Application id of the Service Principal (the API) which has defined the application permission(s) -ApiServicePrincipalAppDisplayName <String> Display name of the Service Principal (the API) which has defined the application permission(s) -ApplicationPermissionScopes <String> The application permission scopes you want to assign to the Service Principal, and are defined by the Api Service Principal
You can see that the additional scopes are now added to the Managed Identity:
It's easier to give your Service Principal permissions to another Azure resource as this can be achieved through the UI, but with my script, it's almost as easy to give API permissions as well!
As an added perk: the Microsoft Graph cmdlets work really well in the unattended fashion of a DevOps pipeline, so combine it with this script and you can make sure all your Managed Identities have the correct permissions assigned through your automated deployment pipelines!