Orphaned Azure Security Principals Clean-up & Azure Policy Managed Identity Role Assignment Automation

This blog covers 2 topics : (1) how you can automate clean-up of any orphaned security principal role assignments – shown as ‘identity not found’ role assignments.

(2) Secondly, I am showing how you can implement a daily quality-assurance process for Azure Policy Managed Identity Role Assignment to enforce Azure Policy remediation is always working. It is important to run this with a defined frequency, as Azure Policy might stop to work, if role assignments are deleted or policy definition is changed after initial deployment.

You can download the script on my github to implement both automations in your environment. I use the script as part of implementing a desired-state / quality-assurance process, to keep Azure “clean” without leftovers – and to ensure Azure Policy compliance enforcement is working as expected.

This blog also covers how you can extract most information from Azure Resource Graph.

(1) Automation of clean-up of unknown/orphaned security principals e.g. managed identities

You might recall orphaned security principals in the “old” days in Active Directory environments, when looking at e.g. NTFS permissions, Group Policy delegations, etc. You can also find such orphaned objects in Azure.

If you check Access Control (IAM) role assignments within the Azure portal, you might have noticed a security principal listed as “Identity not found” with an “Unknown” type.

This happens when a security principal was delegated role assignments inside Azure – but then the security principal was deleted BEFORE the role assignment was removed.

I will refer to this as a ‘orphaned security principal’.

It is important to note, that a security principal can be any of these 4 types:

  • User
  • Group
  • Service Principal
  • Managed Identity

This means, that if you delete the security principal before deleting the role assignment, you will see an orphaned security principal with “identity not found” (unknown). Below I have added a few real-world examples:

Security PrincipalExample
Deletion of guest userLast year, you invited an external consultant to assist on a project using an Azure guest user. You delegate Contributor permissions on an Azure subscription.
 
Project has now completed. You delete the Azure guest-user, but forget to delete the role assignment.
   or
Your security department has enforced automatic deletion of guests, who hasn’t signed in during the last 180 days.  The external consultant will be automatically deleted.
Delegation of Active Directory hybrid groupYou delegate Contributor permissions on an Azure subscription using Active Directory hybrid groups, which are synced to Azure AD using AD Connect.
 
After some time, you decide to transition into using native Azure AD cloud groups. You delete the groups in Active Directory and the groups are automatically deleted in Azure AD using AD Connect sync.
 
Now you will end up with an orphaned security principal, originally of the type ‘group’ – but now it will show as unknown, and should be deleted.
Deletion of Azure App service principleYou have an Azure app service principal, that is delegated Read permissions on 2 resource groups in subscription.
 
Now you delete the Azure app service principle, resulting in an orphaned security principle, originally of the type of service principal.
Deletion of managed identityYou are using Microsoft Sentinel automations using Azure Logic Apps. You enable a system-assigned managed identity on a logic app, which is delegated permissions to run the logic app and do different tasks. You now delete the logic app – and will end up with an orphaned service principal as shown below.
   or
Using code, you provision an Azure Policy and create a managed identity and delegate the required role permissions.
 
Now you delete the policy assignment using code, which results in an orphaned managed identity object.

As you can see from the above examples, there are many situations, which will result in these orphaned security principals. If you are like me, wanting your Azure to be looking “clean”, you will want to automate clean-up of these objects.

How can I see the orphaned accounts ?

Currently, Azure Resource Graph doesn’t support showing Role Assignments, so the only way to detect these, is to traverse the resource tree (management group, subscription, resource groups) to detect orphaned accounts.

You can use Get-AzRoleAssignment to extract the information

NOTE: If you are using Get-AzRoleAssignment, but dont see your ‘unknown’ objects, this is typically caused by running an older version of Az.Resources, which is having bug.

Get-AzRoleAssignment gets basic directory object information from the API and queries further information about the directory object by either AAD or MSGraph api, depending on the version, you have installed.

  • In Az.Resources < 5.1.0, the Get-AzRoleAssignment command depends on the response from AAD graph. It detects the SP is not found and marks the object type as unknown.
  • In Az.Resources >=5.1.0, the cmdlet takes the information from MSGraph. In earlier versions, there was a bug, which was fixed in recent update.

Please run update-module Az.Resources (or update-module Az) to update your Az-modules to newest version.

Highlevel steps to delete orphaned Security Principals:

I use the following 3 steps to delete orphaned Security Principals:

  1. Extract the resource tree (scope) using Azure Resource Graph of all management groups, subscriptions and resource groups.
    • You can do scoping on both management group or tenant-wide level.
  2. Traverse through each entry and check for orphaned security Principles using
    • Get-AzRoleAssignment -Scope $PolAssign | Where-Object { $_.ObjectType -eq ‘Unknown’ }
    • If objects are found, both object and location are added to $Orphaned_Accounts object
  3. Deletion-process can be be done automatically – or a validation process can be added with a ticket for approval. If you want to delete the orphaned object, you will use the following cmdlet

I run the script as a daily task to ensure the environment shines and don’t have any leftovers 😊

Query to extract scope from Azure Resource Graph

I use the following 3 queries to extract the management groups, subscriptions and resource groups using Azure Resource Graph

Management Groupresourcecontainers
| where type == ‘microsoft.management/managementgroups’
| extend mgParent = properties.details.managementGroupAncestorsChain
| mv-expand with_itemindex=MGHierarchy mgParent
| project id, name, properties.displayName, mgParent, MGHierarchy, mgParent.name
| sort by MGHierarchy asc
Subscriptionresourcecontainers
| where type == ‘microsoft.resources/subscriptions’
Resource Groupresourcecontainers
| where type == ‘microsoft.resources/subscriptions/resourcegroups’

(2) Azure Policy Managed Identity Role Assignment Automation

The other maintenance task, which is covered by my script, automates addition of missing managed identity, needed to be able to remediate Azure Policies to enforce compliance on your Azure resources.

I can think of 3 scenarios, where I have seen the need to automate creation of a managed identity role delegation:

  • Timing issue when trying to do role delegations after creating a managed identity as part of Azure policy assignment using code
    • When you create a managed identity as part of a Azure policy assignment, Azure must be replicated before you can do a role delegation. If you deploy 200 policies, approx 10-15% of my policies happens to fail on the initial run due to this replication issue.
  • Changing policy definition after initial deployment
    • If you start by having a policy definition, which runs in audit-mode – and then later change it to deployIfNotExists or modify, then you need to a role delegation through a managed identity.
  • Deletion of managed identity role permissions by mistake – by an admin or service principal with delete permissions
    • If an subscription owner by mistake deletes a managed identity needed to enforce Microsoft Defender for Cloud policies on subscription-level. Some of the settings needed to enforce Microsoft Defender for Cloud, are controlled by Azure Policies being deployed on subscription-level. They need a managed identity and role delegations to enforce configuration. Both User Access Administrators and Owners can delete managed identities.

Instead of relying entirely on script delay-functions, I have chosen to implement a quality-assurance process, which ensures all policies are having the required managed identities with the needed role permissions. Think of it as it will enforce a ‘desired-state’ using automation.

To stay compliant, I automate this process to run as part of a daily maintenance task, so my Azure policies can run successfully.

Azure Policies deep-dive

Resources that are non-compliant to policies with deployIfNotExists or modify effects can be put into a compliant state through Remediation. Remediation is accomplished through remediation tasks that deploy the deployIfNotExists template or the modify operations of the assigned policy on your existing resources and subscriptions, whether that assignment is on a management group, subscription, resource group, or individual resource.

How remediation access control works

When Azure Policy starts a template deployment when evaluating deployIfNotExists policies or modifies a resource when evaluating modify policies, it does so using a managed identity that is associated with the policy assignment.

Policy assignments use managed identities for Azure resource authorization. You can use either a system-assigned managed identity that is created by the policy service or a user-assigned identity provided by the user.

The managed identity needs to be assigned the minimum role-based access control (RBAC) role(s) required to remediate resources.

If the managed identity is missing roles, an error is displayed in the portal during the assignment of the policy or an initiative.

When using the portal, Azure Policy automatically grants the managed identity the listed roles once assignment starts.

When using an Azure software development kit (SDK), the roles must manually be granted to the managed identity.

The location of the managed identity doesn’t impact its operation with Azure Policy.

NOTE: Changing a policy definition does not automatically update the assignment or the associated managed identity.

Remediation security can be configured through the following 4 steps:

(1) Configure the policy definition

As a prerequisite, the policy definition must define the roles that deployIfNotExists and modify need to successfully deploy the content of the included template.

No action is required for a built-in policy definition because these roles are prepopulated.

For a custom policy definition, under the details property, add a roleDefinitionIds property. This property is an array of strings that match roles in your environment. For a full example, see the deployIfNotExists example or the modify examples.

JSONCopy
"details": {
    ...
    "roleDefinitionIds": [
        "/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/{roleGUID}",
        "/providers/Microsoft.Authorization/roleDefinitions/{builtinroleGUID}"
    ]
}

The roleDefinitionIds property uses the full resource identifier and doesn’t take the short roleName of the role.

Permissions should be restricted to the smallest possible set when defining roleDefinitionIds within a policy definition or assigning permissions to a managed identity manually.

See managed identity best practice recommendations for more best practices.

2) Configure the managed identity

Each Azure Policy assignment can be associated with only one managed identity. However, the managed identity can be assigned multiple roles. Configuration occurs in two steps: first create either a system-assigned or user-assigned managed identity, then grant it the necessary roles.

NOTE: When creating a managed identity through the portal, roles will be granted automatically to the managed identity. If roleDefinitionIds are later edited in the policy definition, the new permissions must be manually granted, even in the portal.

(3) Create the managed identity

When creating an assignment using the portal, Azure Policy can generate a system-assigned managed identity and grant it the roles defined in the policy definition’s roleDefinitionIds. Alternatively, you can specify a user-assigned managed identity that receives the same role assignment.

To set a system-assigned managed identity in the portal:

  1. On the Remediation tab of the create/edit assignment view, under Types of Managed Identity, ensure that System assigned managed identity is selected.
  2. Specify the location at which the managed identity is to be located.

To set a user-assigned managed identity in the portal:

  1. On the Remediation tab of the create/edit assignment view, under Types of Managed Identity, ensure that User assigned managed identity is selected.
  2. Specify the scope where the managed identity is hosted. The scope of the managed identity does not have to equate to the scope of the assignment, but it must be in the same tenant.

Under Existing user assigned identities, select the managed identity.

(4) Grant permissions to the managed identity through defined roles

If the managed identity does not have the permissions needed to execute the required remediation task, it will be granted permissions automatically only through the portal. You may skip this step if creating a managed identity through the portal.

For all other methods, the assignment’s managed identity must be manually granted access through the addition of roles, or else the remediation deployment will fail.

Example scenarios that require manual permissions:

  • If the assignment is created through an Azure software development kit (SDK)
  • If a resource modified by deployIfNotExists or modify is outside the scope of the policy assignment
  • If the template accesses properties on resources outside the scope of the policy assignment

There are two ways to grant an assignment’s managed identity the defined roles using the portal: by using Access control (IAM) or by editing the policy or initiative assignment and selecting Save.

To add a role to the assignment’s managed identity, follow these steps:

  1. Launch the Azure Policy service in the Azure portal by selecting All services, then searching for and selecting Policy.
  2. Select Assignments on the left side of the Azure Policy page.
  3. Locate the assignment that has a managed identity and select the name.
  4. Find the Assignment ID property on the edit page. The assignment ID will be something like:
/subscriptions/{subscriptionId}/resourceGroups/PolicyTarget/providers/Microsoft.Authorization/policyAssignments/2802056bfc094dfb95d4d7a5

The name of the managed identity is the last portion of the assignment resource ID, which is 2802056bfc094dfb95d4d7a5 in this example. Copy this portion of the assignment resource ID.

  • Navigate to the resource or the resources parent container (resource group, subscription, management group) that needs the role definition manually added.
  • Select the Access control (IAM) link in the resources page and then select + Add role assignment at the top of the access control page.
  • Select the appropriate role that matches a roleDefinitionId from the policy definition. Leave Assign access to set to the default of ‘Azure AD user, group, or application’. In the Select box, paste or type the portion of the assignment resource ID located earlier. Once the search completes, select the object with the same name to select ID and select Save.

4 thoughts on “Orphaned Azure Security Principals Clean-up & Azure Policy Managed Identity Role Assignment Automation”

  1. Hi

    Great script – thanks.

    Is there any reason you’ve grouped these two tasks together in one script rather than creating two separate scripts to do the tasks separately?

    Regards
    Jeff

    Reply
    • Good comment. Orinally I saw this problem related to managed identies that was deleted so it was my script for managed identity management (incl policy managed identity). But I realized that orphaned managed identies could happend to any type of security principle but I newer separated the script apart. But the structure with the scoping headers and the 2 groupings easily should allow you to separate them.

      Reply

Leave a Reply