Sapir’s failed research blog

Managed identities overview (Part1)


This time we will try to understand managed identities.
Next time, i will try to understand it better from more offensive side 😉

So, what is this all about?

Let’s recap applications and service principals first.

The relationship between an application and a service principal is one to many.

Application is an instance you create in one tenant, and it has a service principal associated with it.

If a client (with a different tenant) wants to use your application, it will create a service principal instance for your application in its own tenant.

The best way to explain this is using a diagram:

The service principal only exists in your tenant. You can assign permissions to it, add certificate or secret for it and in some cases, authenticate with it!

The permissions you give to the SP in your tenant, are the permissions the associated app (local or external) has in your tenant.

This happens by default with Microsoft applications, in the diagram you can see the SharePoint application. This application resides in MS tenant, but it has a SP that represents it on every client tenant. This type of apps (MS apps), called “First-Party” applications.

This is nice, but what has to do with managed identities?

So managed identities are basically a sub-type of service principals.

The purpose is to allow applications to acquire tokens (MS Entra tokens), without need to manage any credentials.

Managed identities are linked to resources. Let’s understand what the means:

We have 2 resources:

  1. VM
  2. DB

If my VM wants to access the DB and read its content, it needs to have read permission on it.

  • Note: since these are resources, and not Entra objects, we are talking about RBAC permissions

If the application on our VM have the right permissions, it still needs to acquire a token that will allow it to access the other resource – the DB.

Here we can use managed identities!

Let’s build a diagram here as well:

The managed identity here is linked to the VM resource.

If the resource will be deleted, so does the MI.

  • This is only True for System assigned managed identity. We will talk about it in a minute.

Just to make it clearer, let’s use Graph API to read managed identity in our tenant, and see its attributes.

This is interesting, when you search the MS documentation for managed identity “GET” query, you see this:

MS documnetation
GET https://graph.microsoft.com/beta/external/authorizationSystems/{id}/microsoft.graph.azureAuthorizationSystem/associatedIdentities/managedIdentities/YWJkNjM1ZTUtNTUyOC00NTY1LThjYWYtZjJjNjBmNGY4MGY4

It feels a bit weird, what “external” has to do with that and what it “authorizationSystems/id”? 

I don’t know to answer these questions, but I do know, this is not the way to get managed identities. The was is actually very simple!

We just need to perform the good old “servicePrincipals” query, and filter for “ManagedIdentity”.

https://graph.microsoft.com/beta/servicePrincipals?$filter=servicePrincipalType+eq+'ManagedIdentity'

Now we can see what managed identity looks like. 

{
            "id": "8c7d7ffb-cd90-4d9e-beca-b73e60ca3f01",
            "deletedDateTime": null,
            "accountEnabled": true,
            "alternativeNames": [
                "isExplicit=False",
                "/subscriptions/84945766-aaff-413d-bf94-2e9743f7693a/resourcegroups/sapir_resource_group/providers/Microsoft.Compute/virtualMachines/sapir-vm"
            ],
            "createdDateTime": "2024-07-13T09:22:22Z",
            "deviceManagementAppType": null,
            "appDescription": null,
            "appDisplayName": null,
            "appId": "f5c8f961-4667-4a12-afdc-e58090afffd9",
            "applicationTemplateId": null,
            "appOwnerOrganizationId": null,
            "appRoleAssignmentRequired": false,
            "description": null,
            "disabledByMicrosoftStatus": null,
            "displayName": "sapir-vm",
            "errorUrl": null,
            "homepage": null,
            "isAuthorizationServiceEnabled": false,
            "isManagementRestricted": null,
            "loginUrl": null,
            "logoutUrl": null,
            "notes": null,
            "notificationEmailAddresses": [],
            "preferredSingleSignOnMode": null,
            "preferredTokenSigningKeyEndDateTime": null,
            "preferredTokenSigningKeyThumbprint": null,
            "publisherName": null,
            "replyUrls": [],
            "samlMetadataUrl": null,
            "samlSLOBindingType": "httpRedirect",
            "servicePrincipalNames": [
                "f5c8f961-4667-4a12-afdc-e58090afffd9",
                "https://identity.azure.net/dfCNK0Uw80pL0J60p5CfdsiKkChL/iqhXbfzT68pI1E="
            ],
            "servicePrincipalType": "ManagedIdentity",
            "signInAudience": null,
            "tags": [],
            "tokenEncryptionKeyId": null,
            "certification": null,
            "info": null,
            "samlSingleSignOnSettings": null,
            "addIns": [],
            "api": {
                "resourceSpecificApplicationPermissions": []
            },
            "appRoles": [],
            "keyCredentials": [],
            "publishedPermissionScopes": [],
            "passwordCredentials": [],
            "resourceSpecificApplicationPermissions": [],
            "verifiedPublisher": {
                "displayName": null,
                "verifiedPublisherId": null,
                "addedDateTime": null
            }
        }

Something that’s worth mentioning, you can see that this servicePrincipal has an “appId” value. But if you try to look for it in your tenant, you’ll see it does not exist.

Managed identities are not tied to applications, they are tied to resources, so the GUID you see in the appId field, is just a random generated GUID meant to support the fact that ServicePrincipals objects always have “appId” associated with them. 

There are 2 types of managed identities:

  1. System assigned
  2. User assigned

System assigned MI is always bound to only one resource.

User assigned MI can be bound to multiple resources. The idea here is that if you have multiple resources that require the same permissions set, you can assign the same managed identity to all of them.

Resources can have both, it can always have 1 system assigned MI, and several users assigned MI.

With user assigned MI, you first create the MI, assign permissions to it, and then assign it to any resource you want.

With system assigned MI, you just need to check the “status” to “on”.

If we want to know if a MI is user assigned or system assigned, we can check the “alternativeNames”. 

Example:

/subscriptions/84945766-aaff-413d-bf94-2e9743f7693a/resourcegroups/sapir_resource_group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/sapir_ua_mi

First thing I thought about was, can I add credentials to managed identities and sign-in with them? As we know this is optional for Service Principals.

Well. The answer here is no.

Ok, it was worth a try.

Now, the next interesting question is “How managed identities acquire tokens?” and “What does a managed identity token look like?”

Let’s answer those (:

I think it’s easier to first look at the token.

I’m going to get a token for a managed identity tied to a VM resource, since:

  1. It’s probably the easiest
  2. It’s the most documented approach

To get a resource token, you need to be on the resource, so only from the VM I will be able to acquire the token (We will understand it better after we speak about token acquiring process)

So, I need a VM with Managed Identity enabled status. I’ll start with the system assigned MI.

When creating the VM, I ticked the checkbox for manage identity.

Now, as I logged in to the VM, I can authenticate with the managed identity in multiple ways.

I can run the following command:

Connect-AzAccount -Identity

I can also create a web request:

$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' -Method GET -Headers @{Metadata="true"}

This request asks for a token to the “management.azure.com” resource.

It requests the token from the following IP: 169.254.169.254

This is known as the IMDS (Azure Instance Metadata Service)

This instance is used to manage virtual machines.

I received the following token:

{ "typ": "JWT",
 "alg": "RS256",
 "x5t": "MGLqj98VNLoXaFfpJCBpgB4JaKs",
 "kid": "MGLqj98VNLoXaFfpJCBpgB4JaKs" 
}.
{"aud": "https://management.azure.com/",
 "iss": "https://sts.windows.net/eba5ea9a-b43a-4fab-af1d-f245e133078d/", 
 "iat": 1720866122,
 "nbf": 1720866122,
 "exp": 1720952822,
 "aio": "E2dgYFgatTRLqeZzTkV17vLTBR8eAAA=",
 "appid": "f5c8f961-4667-4a12-afdc-e58090afffd9",
 "appidacr": "2",
 "idp": "https://sts.windows.net/eba5ea9a-b43a-4fab-af1d-f245e133078d/", 
 "idtyp": "app",
 "oid": "8c7d7ffb-cd90-4d9e-beca-b73e60ca3f01",
 "rh": "0.ARMBmuql6zq0q0-vHfJF4TMHjUZIf3kAutdPukPawfj2MBMTAQA.",
 "sub": "8c7d7ffb-cd90-4d9e-beca-b73e60ca3f01",
 "tid": "eba5ea9a-b43a-4fab-af1d-f245e133078d", 
 "uti": "xqdVPppWUEa7Iq_f5eqnAA",
 "ver": "1.0",
 "xms_idrel": "22 7",
 "xms_mirid": "/subscriptions/84945766-aaff-413d-bf94-2e9743f7693a/resourcegroups/sapir_resource_group/providers/Microsoft.Compute/virtualMachines/sapir-vm",
 "xms_tcdt": "1720437592" 
}.[Signature]

After converting the expiration time, it’s clear that this token is available for a day, which is quite different from users’ AT, which normally expires after 75 minutes (on average).

Another thing that is different, is that MI doesn’t have refresh tokens. The application refreshes its AT every day.

If we check the sub, we will see the servicePrincipalId of our managed identity.

Another new fun attribute is the “xms_mirid”, this is the managed identity resource id identifier.

BTW, this is also one of the “alternativeName” of this SP.

One thing I tried to do is to ask for a token to different services.

I tried AADGraph and MSGraph.

I was able to get the tokens, but once I tried to use the token to call AADGraph, I got an error:

” The user identity header is invalid.”

When I assigned my managed identity reader permission on my subscription, I was able to use the token I obtained for the resource manager and query all the possible information.

This understanding, alongside this great article by Roee Sagi from 2021 (!!) https://orca.security/resources/blog/azure-ad-iam-part-ii-leveraging-managed-identities-for-privilege-escalation/ , highlights the fact that access to some resources with managed identity can accomplish privilege escalation.

It all depends on the RBAC of that MI, therefore, here is a code that reads all the MI, and prints their RBAC and some extra information. 

Then you can search the table for the permissions that you want, and see if you can get them by using the associated resource!

az login
$sps = az ad sp list --filter "servicePrincipalType eq 'ManagedIdentity'" | ConvertFrom-Json
foreach($sp in $sps)
{
     Write-Host "Managed Identity:`r`n Id: $($sp.id)`r`n Name: $($sp.displayName)"
     $rbac = az role assignment list --assignee  $sp.id | ConvertFrom-Json
     foreach($r in $rbac)
     {
        Write-Host "RBAC:`r`n $($r.roleDefinitionId)`r`n $($r.roleDefinitionName)`r`n $($r.scope)"
     }
     Write-Host "`r`n==========================================================`r`n"
}
 

output:

Leave a comment