{"id":938,"date":"2023-02-06T03:31:45","date_gmt":"2023-02-06T02:31:45","guid":{"rendered":"https:\/\/mortenknudsen.net\/?p=938"},"modified":"2023-02-06T04:28:08","modified_gmt":"2023-02-06T03:28:08","slug":"orphaned-azure-security-principals-clean-up-azure-policy-managed-identity-role-assignment-automation","status":"publish","type":"post","link":"https:\/\/mortenknudsen.net\/?p=938","title":{"rendered":"Orphaned Azure Security Principals Clean-up &#038; Azure Policy Managed Identity Role Assignment Automation"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This blog covers 2 topics : (1) how you can <strong>automate clean-up of any orphaned security principal role assignments<\/strong> &#8211; shown as <strong>&#8216;identity not found&#8217;<\/strong> role assignments.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"309\" src=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_2-1024x309.png\" alt=\"\" class=\"wp-image-940\" srcset=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_2-1024x309.png 1024w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_2-300x91.png 300w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_2-768x232.png 768w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_2-1536x464.png 1536w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_2.png 1997w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">(2) Secondly, I am showing how you can implement a daily quality-assurance process for <strong>Azure Policy Managed Identity Role Assignment <\/strong>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. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"373\" src=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-Adding-1024x373.png\" alt=\"\" class=\"wp-image-941\" srcset=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-Adding-1024x373.png 1024w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-Adding-300x109.png 300w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-Adding-768x280.png 768w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-Adding-1536x559.png 1536w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-Adding-2048x746.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can <a href=\"https:\/\/github.com\/KnudsenMorten\/AzureAAD-ManagedId-RoleAssignmentsCleanupOrphanedAccounts\" target=\"_blank\" rel=\"noreferrer noopener\">download the script on my github<\/a> to implement <strong>both automations<\/strong> in your environment. I use the script as part of implementing a <strong>desired-state \/ quality-assurance process<\/strong>, to keep Azure &#8220;clean&#8221; without leftovers &#8211; and to ensure Azure Policy compliance enforcement is working as expected. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This blog also covers how you can extract most information from <strong>Azure Resource Graph<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">(1) <strong>Automation of clean-up of unknown\/orphaned security principals e.g. managed identities<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You might recall orphaned security principals in the \u201cold\u201d 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you check Access Control (IAM) role assignments within the Azure portal, you might have noticed a <strong>security principal<\/strong> listed as <strong>\u201cIdentity not found\u201d with an \u201cUnknown\u201d type<\/strong>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This happens when a security principal was delegated role assignments inside Azure \u2013 but then the security principal was deleted BEFORE the role assignment was removed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I will refer to this as a \u2018<strong>orphaned security principal<\/strong>\u2019.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2467\" height=\"670\" src=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header.png\" alt=\"\" class=\"wp-image-971\" srcset=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header.png 2467w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header-300x81.png 300w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header-1024x278.png 1024w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header-768x209.png 768w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header-1536x417.png 1536w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header-2048x556.png 2048w\" sizes=\"auto, (max-width: 2467px) 100vw, 2467px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is important to note, that a security principal can be any of these 4 types:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>User<\/strong><\/li>\n\n\n\n<li><strong>Group<\/strong><\/li>\n\n\n\n<li><strong>Service Principal<\/strong><\/li>\n\n\n\n<li><strong>Managed Identity<\/strong><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This means, that if you delete the security principal before deleting the role assignment, you will see an orphaned security principal with &#8220;identity not found&#8221; (unknown). Below I have added a few real-world examples:<\/p>\n\n\n\n<figure class=\"wp-block-table has-small-font-size\"><table><tbody><tr><td>Security Principal<\/td><td>Example<\/td><\/tr><tr><td>Deletion of <strong>guest user<\/strong><\/td><td>Last year, you invited an external consultant to assist on a project using an Azure guest user. You delegate Contributor permissions on an Azure subscription.<br>&nbsp;<br>Project has now completed. You delete the Azure guest-user, but forget to delete the role assignment.<br>&nbsp;&nbsp; or<br>Your security department has enforced automatic deletion of guests, who hasn\u2019t signed in during the last 180 days. &nbsp;The external consultant will be automatically deleted.<\/td><\/tr><tr><td>Delegation of <strong>Active Directory hybrid group<\/strong><\/td><td>You delegate Contributor permissions on an Azure subscription using Active Directory hybrid groups, which are synced to Azure AD using AD Connect.<br>&nbsp;<br>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.<br>&nbsp;<br>Now you will end up with an orphaned security principal, originally of the type \u2018group\u2019 \u2013 but now it will show as unknown, and should be deleted.<\/td><\/tr><tr><td>Deletion of <strong>Azure App service principle<\/strong><\/td><td>You have an Azure app service principal, that is delegated Read permissions on 2 resource groups in subscription.<br>&nbsp;<br>Now you delete the Azure app service principle, resulting in an orphaned security principle, originally of the type of service principal.<\/td><\/tr><tr><td>Deletion of <strong>managed identity<\/strong><\/td><td>You 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 \u2013 and will end up with an orphaned service principal as shown below.<br>&nbsp;&nbsp; or<br>Using code, you provision an Azure Policy and create a managed identity and delegate the required role permissions.<br>&nbsp;<br>Now you delete the policy assignment using code, which results in an orphaned managed identity object.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">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 \u201cclean\u201d, you will want to automate clean-up of these objects.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>How can I see the orphaned accounts ?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Currently, Azure Resource Graph doesn\u2019t 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can use <strong>Get-AzRoleAssignment<\/strong> to extract the information<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>NOTE<\/strong>:  If you are using Get-AzRoleAssignment, but dont see your \u2018unknown\u2019 objects, this is typically caused by running an older version of Az.Resources, which is having bug.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In Az.Resources &lt; 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.<\/li>\n\n\n\n<li>In Az.Resources &gt;=5.1.0, the cmdlet takes the information from MSGraph. In earlier versions, there was a bug, which was fixed in recent update.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Please run <strong>update-module Az.Resources <\/strong>(or update-module Az) to update your Az-modules to newest version.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong><u>Highlevel steps to delete orphaned Security Principals:<\/u><\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I use the following 3 steps to <strong>delete orphaned Security Principals<\/strong>:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>Extract the <strong>resource tree<\/strong> (scope) using <strong>Azure Resource Graph<\/strong> of all <strong>management groups, subscriptions<\/strong> and <strong>resource groups<\/strong>. \n<ul class=\"wp-block-list\">\n<li>You can do scoping on both management group or tenant-wide level.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Traverse through each entry and check for orphaned security Principles using\n<ul class=\"wp-block-list\">\n<li>Get-AzRoleAssignment -Scope $PolAssign | Where-Object { $_.ObjectType -eq &#8216;Unknown&#8217; }<\/li>\n\n\n\n<li>If objects are found, both object and location are added to $Orphaned_Accounts object<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Deletion-process can be be done automatically \u2013 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<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2134\" height=\"300\" src=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-scope-1.png\" alt=\"\" class=\"wp-image-951\" srcset=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-scope-1.png 2134w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-scope-1-300x42.png 300w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-scope-1-1024x144.png 1024w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-scope-1-768x108.png 768w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-scope-1-1536x216.png 1536w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-scope-1-2048x288.png 2048w\" sizes=\"auto, (max-width: 2134px) 100vw, 2134px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"240\" src=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-found4-1-1024x240.png\" alt=\"\" class=\"wp-image-962\" srcset=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-found4-1-1024x240.png 1024w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-found4-1-300x70.png 300w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-found4-1-768x180.png 768w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-found4-1-1536x361.png 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"3143\" height=\"684\" src=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_4_remove.png\" alt=\"\" class=\"wp-image-947\" srcset=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_4_remove.png 3143w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_4_remove-300x65.png 300w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_4_remove-1024x223.png 1024w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_4_remove-768x167.png 768w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_4_remove-1536x334.png 1536w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI_4_remove-2048x446.png 2048w\" sizes=\"auto, (max-width: 3143px) 100vw, 3143px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"3171\" height=\"800\" src=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-RemovedMI-1.png\" alt=\"\" class=\"wp-image-949\" srcset=\"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-RemovedMI-1.png 3171w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-RemovedMI-1-300x76.png 300w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-RemovedMI-1-1024x258.png 1024w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-RemovedMI-1-768x194.png 768w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-RemovedMI-1-1536x388.png 1536w, https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/MI-RemovedMI-1-2048x517.png 2048w\" sizes=\"auto, (max-width: 3171px) 100vw, 3171px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I run the script as a daily task to ensure the environment shines and don\u2019t have any leftovers \ud83d\ude0a<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Query to extract scope from Azure Resource Graph<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I use the following 3 queries to extract the management groups, subscriptions and resource groups using Azure Resource Graph<\/p>\n\n\n\n<figure class=\"wp-block-table has-small-font-size\"><table><tbody><tr><td>Management Group<\/td><td>resourcecontainers<br>| where type == \u2018microsoft.management\/managementgroups\u2019<br>| extend mgParent = properties.details.managementGroupAncestorsChain<br>| mv-expand with_itemindex=MGHierarchy mgParent<br>| project id, name, properties.displayName, mgParent, MGHierarchy, mgParent.name<br>| sort by MGHierarchy asc<\/td><\/tr><tr><td>Subscription<\/td><td>resourcecontainers<br>| where type == \u2018microsoft.resources\/subscriptions\u2019<\/td><\/tr><tr><td>Resource Group<\/td><td>resourcecontainers<br>| where type == \u2018microsoft.resources\/subscriptions\/resourcegroups\u2019<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">(2) Azure Policy Managed Identity Role Assignment Automation<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The other maintenance task, which is covered by my script, <strong>automates addition of missing managed identity<\/strong>, needed <strong>to be able to remediate Azure Policies<\/strong> to enforce compliance on your Azure resources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I can think of 3 scenarios, where I have seen the need to <strong>automate creation of a managed identity role delegation<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Timing issue when trying to do role delegations after creating a managed identity as part of Azure policy assignment using code<\/strong>\n<ul class=\"wp-block-list\">\n<li>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.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Changing policy definition after initial deployment<\/strong>\n<ul class=\"wp-block-list\">\n<li>If you start by having a policy definition, which runs in <strong>audit<\/strong>-mode \u2013 and then later change it to <strong>deployIfNotExists<\/strong> or <strong>modify<\/strong>, then you need to a role delegation through a managed identity.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Deletion of managed identity role permissions by mistake \u2013 by an admin or service principal with delete permissions<\/strong>\n<ul class=\"wp-block-list\">\n<li>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.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of relying entirely on script delay-functions, I have chosen to implement a <strong>quality-assurance process<\/strong>, which ensures all policies are having the <strong>required<\/strong> <strong>managed identities with the needed role permissions<\/strong>. Think of it as it will enforce a \u2018desired-state\u2019 using automation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To stay compliant, I automate this process to run as part of a daily maintenance task, so my Azure policies can run successfully.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Azure Policies deep-dive<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Resources that are non-compliant to policies with&nbsp;<strong>deployIfNotExists<\/strong>&nbsp;or&nbsp;<strong>modify<\/strong>&nbsp;effects can be put into a compliant state through&nbsp;<strong>Remediation<\/strong>. Remediation is accomplished through&nbsp;<strong>remediation tasks<\/strong>&nbsp;that deploy the&nbsp;<strong>deployIfNotExists<\/strong>&nbsp;template or the&nbsp;<strong>modify<\/strong>&nbsp;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. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>How remediation access control works<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When Azure Policy starts a template deployment when evaluating&nbsp;<strong>deployIfNotExists<\/strong>&nbsp;policies or modifies a resource when evaluating&nbsp;<strong>modify<\/strong>&nbsp;policies, it does so using a&nbsp;<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/managed-identities-azure-resources\/overview\">managed identity<\/a>&nbsp;that is associated with the policy assignment. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Policy assignments use&nbsp;<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/managed-identities-azure-resources\/overview\">managed identities<\/a>&nbsp;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. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The managed identity needs to be assigned the minimum role-based access control (RBAC) role(s) required to remediate resources. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the managed identity is missing roles, an error is displayed in the portal during the assignment of the policy or an initiative. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When using the portal, Azure Policy automatically grants the managed identity the listed roles once assignment starts. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When using an Azure software development kit (SDK), the roles must manually be granted to the managed identity. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<em>location<\/em>&nbsp;of the managed identity doesn&#8217;t impact its operation with Azure Policy.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>NOTE<\/strong>:  Changing a policy definition does not automatically update the assignment or the associated managed identity.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Remediation security can be configured through the following 4 steps:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">(1) Configure the policy definition<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As a prerequisite, the policy definition must define the roles that <strong>deployIfNotExists<\/strong> and <strong>modify<\/strong>&nbsp;need to successfully deploy the content of the included template. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">No action is required for a built-in policy definition because these roles are prepopulated. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a custom policy definition, under the&nbsp;<strong>details<\/strong>&nbsp;property, add a&nbsp;<strong>roleDefinitionIds<\/strong>&nbsp;property. This property is an array of strings that match roles in your environment. For a full example, see the&nbsp;<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/governance\/policy\/concepts\/effects#deployifnotexists-example\">deployIfNotExists example<\/a>&nbsp;or the&nbsp;<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/governance\/policy\/concepts\/effects#modify-examples\">modify examples<\/a>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<pre class=\"wp-block-code has-small-font-size\"><code>JSONCopy\n\"details\": {\n    ...\n    \"roleDefinitionIds\": &#91;\n        \"\/subscriptions\/{subscriptionId}\/providers\/Microsoft.Authorization\/roleDefinitions\/{roleGUID}\",\n        \"\/providers\/Microsoft.Authorization\/roleDefinitions\/{builtinroleGUID}\"\n    ]\n}\n<\/code><\/pre>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<strong>roleDefinitionIds<\/strong>&nbsp;property uses the full resource identifier and doesn&#8217;t take the short&nbsp;<strong>roleName<\/strong>&nbsp;of the role. <\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Permissions should be restricted to the smallest possible set when defining&nbsp;<strong>roleDefinitionIds<\/strong>&nbsp;within a policy definition or assigning permissions to a managed identity manually. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">See&nbsp;<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/managed-identities-azure-resources\/managed-identity-best-practice-recommendations\"><strong>managed identity best practice recommendations<\/strong><\/a>&nbsp;for more best practices.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">2) Configure the managed identity<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>NOTE<\/strong>:  When creating a managed identity through the portal, roles will be granted automatically to the managed identity. If&nbsp;<strong>roleDefinitionIds<\/strong>&nbsp;are later edited in the policy definition, the new permissions must be manually granted, even in the portal.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">(3) Create the managed identity<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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&#8217;s&nbsp;<strong>roleDefinitionIds<\/strong>. Alternatively, you can specify a user-assigned managed identity that receives the same role assignment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To set a system-assigned managed identity in the portal:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>On the&nbsp;<strong>Remediation<\/strong>&nbsp;tab of the create\/edit assignment view, under&nbsp;<strong>Types of Managed Identity<\/strong>, ensure that&nbsp;<strong>System assigned managed identity<\/strong>&nbsp;is selected.<\/li>\n\n\n\n<li>Specify the location at which the managed identity is to be located.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">To set a user-assigned managed identity in the portal:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>On the&nbsp;<strong>Remediation<\/strong>&nbsp;tab of the create\/edit assignment view, under&nbsp;<strong>Types of Managed Identity<\/strong>, ensure that&nbsp;<strong>User assigned managed identity<\/strong>&nbsp;is selected.<\/li>\n\n\n\n<li>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.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Under&nbsp;<strong>Existing user assigned identities<\/strong>, select the managed identity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">(4) Grant permissions to the managed identity through defined roles<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If the managed identity does not have the permissions needed to execute the required remediation task, it will be granted permissions&nbsp;<em>automatically<\/em>&nbsp;only through the portal. You may skip this step if creating a managed identity through the portal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For all other methods, the assignment&#8217;s managed identity must be manually granted access through the addition of roles, or else the remediation deployment will fail.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example scenarios that require manual permissions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If the assignment is created through an Azure software development kit (SDK)<\/li>\n\n\n\n<li>If a resource modified by&nbsp;<strong>deployIfNotExists<\/strong>&nbsp;or&nbsp;<strong>modify<\/strong>&nbsp;is outside the scope of the policy assignment<\/li>\n\n\n\n<li>If the template accesses properties on resources outside the scope of the policy assignment<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">There are two ways to grant an assignment&#8217;s managed identity the defined roles using the portal: by using&nbsp;<strong>Access control (IAM)<\/strong>&nbsp;or by editing the policy or initiative assignment and selecting&nbsp;<strong>Save<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To add a role to the assignment&#8217;s managed identity, follow these steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\" type=\"1\">\n<li>Launch the Azure Policy service in the Azure portal by selecting&nbsp;<strong>All services<\/strong>, then searching for and selecting&nbsp;<strong>Policy<\/strong>.<\/li>\n\n\n\n<li>Select&nbsp;<strong>Assignments<\/strong>&nbsp;on the left side of the Azure Policy page.<\/li>\n\n\n\n<li>Locate the assignment that has a managed identity and select the name.<\/li>\n\n\n\n<li>Find the&nbsp;<strong>Assignment ID<\/strong>&nbsp;property on the edit page. The assignment ID will be something like:<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>\/subscriptions\/{subscriptionId}\/resourceGroups\/PolicyTarget\/providers\/Microsoft.Authorization\/policyAssignments\/2802056bfc094dfb95d4d7a5<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The name of the managed identity is the last portion of the assignment resource ID, which is&nbsp;2802056bfc094dfb95d4d7a5&nbsp;in this example. Copy this portion of the assignment resource ID.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Navigate to the resource or the resources parent container (resource group, subscription, management group) that needs the role definition manually added.<\/li>\n\n\n\n<li>Select the&nbsp;<strong>Access control (IAM)<\/strong>&nbsp;link in the resources page and then select&nbsp;<strong>+ Add role assignment<\/strong>&nbsp;at the top of the access control page.<\/li>\n\n\n\n<li>Select the appropriate role that matches a&nbsp;<strong>roleDefinitionId<\/strong>&nbsp;from the policy definition. Leave&nbsp;<strong>Assign access to<\/strong>&nbsp;set to the default of &#8216;Azure AD user, group, or application&#8217;. In the&nbsp;<strong>Select<\/strong>&nbsp;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&nbsp;<strong>Save<\/strong>.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This blog covers 2 topics : (1) how you can automate clean-up of any orphaned security principal role assignments &#8211; &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"Orphaned Azure Security Principals Clean-up &#038; Azure Policy Managed Identity Role Assignment Automation\" class=\"read-more button\" href=\"https:\/\/mortenknudsen.net\/?p=938#more-938\" aria-label=\"Read more about Orphaned Azure Security Principals Clean-up &#038; Azure Policy Managed Identity Role Assignment Automation\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":971,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"ngg_post_thumbnail":0,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[55,57,48,60],"tags":[20,18,126,124,80,123,127,17,125],"class_list":["post-938","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-azure-security","category-defender-for-cloud","category-scripting","tag-automation","tag-azure","tag-identity-not-found","tag-managed-identity","tag-microsoftsecurity","tag-policy","tag-role-assignment","tag-security","tag-unknown","infinite-scroll-item","resize-featured-image"],"featured_image_src":"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header.png","author_info":{"display_name":"Morten Knudsen","author_link":"https:\/\/mortenknudsen.net\/?author=1"},"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack_featured_media_url":"https:\/\/mortenknudsen.net\/wp-content\/uploads\/2023\/02\/mi-header.png","_links":{"self":[{"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=\/wp\/v2\/posts\/938","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=938"}],"version-history":[{"count":25,"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=\/wp\/v2\/posts\/938\/revisions"}],"predecessor-version":[{"id":980,"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=\/wp\/v2\/posts\/938\/revisions\/980"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=\/wp\/v2\/media\/971"}],"wp:attachment":[{"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=938"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=938"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mortenknudsen.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=938"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}