Azure Logic Apps - Authenticate to Microsoft Graph via Managed Service Identity

Apr 22, 2022 8:14 AM

Personal Blog
Microsoft
Azure
Azure Logic Apps
MSI
Microsoft Graph
PowerShell
Azure AD

Improving the process

For the longest time, it hasn't been easy to use the Microsoft Graph. It always came back to having an App registration within Azure AD, with delegated permissions to the Microsoft Graph itself, which you had to give admin privileges in order to let it access the selected permissions.

From that point on you had to make several API calls to get what you needed from the Microsoft Graph, including adding your clientID, TenantID, Username, Password to just get your Access token, which is all quite tedious.

It would be much nicer if this could be done via MSI to avoid making several API calls which include sensitive data. Luckily this is possible, and not just for Logic Apps, but I needed it for my use case.

MSI for Microsoft Graph

If you have created your Logic App, you can assign it a System Assigned Identity via the Identity option under Settings.

Switch Status from Off to On and hit Save. This can also be done if you've created your Logic App via Infrastructure as Code (IaC).

For example via Bicep:

identity: {
   type: 'SystemAssigned'
          }

After saving, you wil get an Object ID (or when rolled out with MSI enabled). Copy this, as you will need it for the next step.

Next up is a bit of Powershell. This can also be done via the Azure CLI, but Powershell should be sufficient for now. If you have an IaC deployment, you can simply run the code after your deployment in the same pipeline.

Why do we actually need Powershell for this step? Well, unfortunately, the following can't be done via the Azure Portal and with this pre-made script things become a lot easier.

Connect-AzureAD
$graph = Get-AzureADServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'"
$Permission = $graph.AppRoles `
    | where Value -Like "Directory.Read.All" `
    | Select-Object -First 1

$msi = Get-AzureADServicePrincipal -ObjectId 4f4a5383-9634-4f05-abfa-e221d9858ba9

New-AzureADServiceAppRoleAssignment `
    -Id $Permission.Id `
    -ObjectId $msi.ObjectId `
    -PrincipalId $msi.ObjectId `
    -ResourceId $graph.ObjectId

So let's look what the above code does! First up, we make a connection with our Azure AD and get the ServicePrincipal from the Microsoft Graph. This AppId will be the same in every Azure Environment and is not specific to mine.

Secondly, we will get the AppRole, which contains the Directory.Read.All permissions. This is what I needed for my use case, but this can be different for you. To see more options, you can look here.

Next, we specify the Logic Apps ObjectID that we copied. As stated, this can also be used for different Azure services such as VMs, Containers, App services, etc.

And lastly, we create a new AppRoleAssignment, giving the Logic App access to the Microsoft Graph for the Directory.Read.All permissions.

After running this code, your Logic App is set to connect to the Microsoft Graph!

The Logic App

To show this example of calling the Microsoft Graph API, I created the following Logic App:

For the sake of convenience you can use the following JSON code below:

{
    "definition": {
        "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
        "actions": {
            "Get_object_properties_from_Microsoft_Graph": {
                "inputs": {
                    "authentication": {
                        "audience": "https://graph.microsoft.com/",
                        "type": "ManagedServiceIdentity"
                    },
                    "headers": {
                        "Content-Type": "application/json"
                    },
                    "method": "GET",
                    "uri": "https://graph.microsoft.com/beta/directoryObjects/{ObjectID}"
                },
                "runAfter": {},
                "type": "Http"
            }
        },
        "contentVersion": "1.0.0.0",
        "outputs": {},
        "parameters": {},
        "triggers": {
            "Recurrence": {
                "evaluatedRecurrence": {
                    "frequency": "Month",
                    "interval": 1,
                    "timeZone": "W. Europe Standard Time"
                },
                "recurrence": {
                    "frequency": "Month",
                    "interval": 1,
                    "timeZone": "W. Europe Standard Time"
                },
                "type": "Recurrence"
            }
        }
    },
    "parameters": {}
}

The Logic App has a simple recurrence of once a month and makes an HTTP Request to the Microsoft Graph while authenticating via MSI. The example uses the directoryObjects call to get all the information about a specific Azure AD component, in my case the Logic App itself.

For my use case, I needed the Displayname of based on an ID. This is the case, because when working with getting RBAC from Azure Services it always specifies the ID but not the Displaynames. With this, I was able to get it and use it in my results. More on this in next week's blog!

To see the full list of possible results you get from the call you can check here.

I hope this made your Microsoft Graph calls a lot easier, as it did for me!

What's next

Let's dive into more Logic Apps, and get a nice security report based on RBAC. Stay tuned!