From d11f6a43fb6be86abaedd30c1988d2f804b77463 Mon Sep 17 00:00:00 2001 From: Jack Tracey Date: Fri, 29 Nov 2024 11:11:03 +0000 Subject: [PATCH 1/7] additional-changes --- .../policy-assignment/main.bicep | 2 + ...t-group-additional-rbac-asi-def-loop.bicep | 29 +++++++++++ ...management-group-additional-rbac-asi.bicep | 23 ++++++++ .../modules/management-group.bicep | 52 +++++++++++++------ 4 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep create mode 100644 avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep diff --git a/avm/ptn/authorization/policy-assignment/main.bicep b/avm/ptn/authorization/policy-assignment/main.bicep index bb2508a723..96177fcf32 100644 --- a/avm/ptn/authorization/policy-assignment/main.bicep +++ b/avm/ptn/authorization/policy-assignment/main.bicep @@ -117,6 +117,8 @@ module policyAssignment_mg 'modules/management-group.bicep' = if (empty(subscrip } } +// Create additional role assignments at different management group scopes if needed + module policyAssignment_sub 'modules/subscription.bicep' = if (!empty(subscriptionId) && empty(resourceGroupName)) { name: '${uniqueString(deployment().name, location)}-PolicyAssignment-Sub-Module' scope: subscription(subscriptionId) diff --git a/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep b/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep new file mode 100644 index 0000000000..b1feaaf6f0 --- /dev/null +++ b/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep @@ -0,0 +1,29 @@ +targetScope = 'managementGroup' + +@sys.description('Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity.') +param additionalManagementGroupsIDsToAssignRbacTo array = [] + +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +module additionalManagementGroupRoleAssignmentsPerMG 'management-group-additional-rbac-asi.bicep' = [ + for mg in additionalManagementGroupsIDsToAssignRbacTo: { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC' + scope: managementGroup(mg) + params: { + name: name + policyAssignmentIdentityId: policyAssignmentIdentityId + roleDefinitionId: roleDefinitionId + } + } +] diff --git a/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep b/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep new file mode 100644 index 0000000000..907f814f6b --- /dev/null +++ b/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep @@ -0,0 +1,23 @@ +targetScope = 'managementGroup' + +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(managementGroup().id, roleDefinitionId, location, name) + properties: { + roleDefinitionId: roleDefinitionId + principalId: policyAssignmentIdentityId + principalType: 'ServicePrincipal' + } +} diff --git a/avm/ptn/authorization/policy-assignment/modules/management-group.bicep b/avm/ptn/authorization/policy-assignment/modules/management-group.bicep index 721899031a..4be8d37d78 100644 --- a/avm/ptn/authorization/policy-assignment/modules/management-group.bicep +++ b/avm/ptn/authorization/policy-assignment/modules/management-group.bicep @@ -35,6 +35,9 @@ param userAssignedIdentityId string = '' @sys.description('Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') param roleDefinitionIds array = [] +@sys.description('Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity.') +param additionalManagementGroupsIDsToAssignRbacTo array = [] + @sys.description('Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') param metadata object = {} @@ -63,14 +66,18 @@ param overrides array = [] @sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location.') param resourceSelectors array = [] -var identityVar = identity == 'SystemAssigned' ? { - type: identity -} : identity == 'UserAssigned' ? { - type: identity - userAssignedIdentities: { - '${userAssignedIdentityId}': {} - } -} : null +var identityVar = identity == 'SystemAssigned' + ? { + type: identity + } + : identity == 'UserAssigned' + ? { + type: identity + userAssignedIdentities: { + '${userAssignedIdentityId}': {} + } + } + : null resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { name: name @@ -90,15 +97,28 @@ resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' identity: identityVar } -resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && identity == 'SystemAssigned') { - name: guid(managementGroupId, roleDefinitionId, location, name) - properties: { - roleDefinitionId: roleDefinitionId - principalId: policyAssignment.identity.principalId - principalType: 'ServicePrincipal' +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && identity == 'SystemAssigned') { + name: guid(managementGroupId, roleDefinitionId, location, name) + properties: { + roleDefinitionId: roleDefinitionId + principalId: policyAssignment.identity.principalId + principalType: 'ServicePrincipal' + } } -}] - +] + +module additionalManagementGroupRoleAssignments 'management-group-additional-rbac-asi-def-loop.bicep' = [ + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && identity == 'SystemAssigned') { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC' + params: { + name: name + policyAssignmentIdentityId: policyAssignment.identity.principalId + roleDefinitionId: roleDefinitionId + additionalManagementGroupsIDsToAssignRbacTo: additionalManagementGroupsIDsToAssignRbacTo + } + } +] @sys.description('Policy Assignment Name.') output name string = policyAssignment.name From 8b4020e2ed5eea61212ad890303d58e060a3d7e9 Mon Sep 17 00:00:00 2001 From: Jack Tracey Date: Fri, 29 Nov 2024 11:13:06 +0000 Subject: [PATCH 2/7] expose top level --- avm/ptn/authorization/policy-assignment/main.bicep | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/avm/ptn/authorization/policy-assignment/main.bicep b/avm/ptn/authorization/policy-assignment/main.bicep index 96177fcf32..bb2f5f17cc 100644 --- a/avm/ptn/authorization/policy-assignment/main.bicep +++ b/avm/ptn/authorization/policy-assignment/main.bicep @@ -50,6 +50,9 @@ param enforcementMode string = 'Default' @sys.description('Optional. The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment.') param managementGroupId string = managementGroup().name +@sys.description('Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity.') +param additionalManagementGroupsIDsToAssignRbacTo array = [] + @sys.description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment.') param subscriptionId string = '' @@ -114,6 +117,7 @@ module policyAssignment_mg 'modules/management-group.bicep' = if (empty(subscrip location: location overrides: !empty(overrides) ? overrides : [] resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] + additionalManagementGroupsIDsToAssignRbacTo: additionalManagementGroupsIDsToAssignRbacTo } } From bead0972f2906c05556239c13391c0a6ce58f319 Mon Sep 17 00:00:00 2001 From: Jack Tracey Date: Fri, 29 Nov 2024 11:14:22 +0000 Subject: [PATCH 3/7] add fitler --- .../policy-assignment/modules/management-group.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/ptn/authorization/policy-assignment/modules/management-group.bicep b/avm/ptn/authorization/policy-assignment/modules/management-group.bicep index 4be8d37d78..a78e6f3ba5 100644 --- a/avm/ptn/authorization/policy-assignment/modules/management-group.bicep +++ b/avm/ptn/authorization/policy-assignment/modules/management-group.bicep @@ -109,7 +109,7 @@ resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ ] module additionalManagementGroupRoleAssignments 'management-group-additional-rbac-asi-def-loop.bicep' = [ - for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && identity == 'SystemAssigned') { + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && !empty(additionalManagementGroupsIDsToAssignRbacTo) && identity == 'SystemAssigned') { name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC' params: { name: name From eb2f6b2a23daa95cad0cd96ba182ae816de1f961 Mon Sep 17 00:00:00 2001 From: Jack Tracey Date: Sat, 30 Nov 2024 14:34:25 +0000 Subject: [PATCH 4/7] updates --- .../policy-assignment/main.bicep | 1 - ...t-group-additional-rbac-asi-def-loop.bicep | 4 ++-- .../modules/management-group.bicep | 22 +++++-------------- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/avm/ptn/authorization/policy-assignment/main.bicep b/avm/ptn/authorization/policy-assignment/main.bicep index bb2f5f17cc..94aeafcef7 100644 --- a/avm/ptn/authorization/policy-assignment/main.bicep +++ b/avm/ptn/authorization/policy-assignment/main.bicep @@ -113,7 +113,6 @@ module policyAssignment_mg 'modules/management-group.bicep' = if (empty(subscrip nonComplianceMessages: !empty(nonComplianceMessages) ? nonComplianceMessages : [] enforcementMode: enforcementMode notScopes: !empty(notScopes) ? notScopes : [] - managementGroupId: managementGroupId location: location overrides: !empty(overrides) ? overrides : [] resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] diff --git a/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep b/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep index b1feaaf6f0..4e8d720922 100644 --- a/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep +++ b/avm/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep @@ -1,7 +1,7 @@ targetScope = 'managementGroup' @sys.description('Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity.') -param additionalManagementGroupsIDsToAssignRbacTo array = [] +param managementGroupsIDsToAssignRbacTo array = [] @sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') param roleDefinitionId string @@ -17,7 +17,7 @@ param name string param policyAssignmentIdentityId string module additionalManagementGroupRoleAssignmentsPerMG 'management-group-additional-rbac-asi.bicep' = [ - for mg in additionalManagementGroupsIDsToAssignRbacTo: { + for mg in managementGroupsIDsToAssignRbacTo: { name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC' scope: managementGroup(mg) params: { diff --git a/avm/ptn/authorization/policy-assignment/modules/management-group.bicep b/avm/ptn/authorization/policy-assignment/modules/management-group.bicep index a78e6f3ba5..2c5c25e0c0 100644 --- a/avm/ptn/authorization/policy-assignment/modules/management-group.bicep +++ b/avm/ptn/authorization/policy-assignment/modules/management-group.bicep @@ -51,9 +51,6 @@ param nonComplianceMessages array = [] ]) param enforcementMode string = 'Default' -@sys.description('Optional. The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment.') -param managementGroupId string = managementGroup().name - @sys.description('Optional. The policy excluded scopes.') param notScopes array = [] @@ -79,6 +76,10 @@ var identityVar = identity == 'SystemAssigned' } : null +var finalArrayOfManagementGroupsToAssignRbacTo = identity == 'SystemAssigned' + ? union(additionalManagementGroupsIDsToAssignRbacTo, [managementGroup().name]) + : [] + resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { name: name location: location @@ -97,25 +98,14 @@ resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' identity: identityVar } -resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ - for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && identity == 'SystemAssigned') { - name: guid(managementGroupId, roleDefinitionId, location, name) - properties: { - roleDefinitionId: roleDefinitionId - principalId: policyAssignment.identity.principalId - principalType: 'ServicePrincipal' - } - } -] - -module additionalManagementGroupRoleAssignments 'management-group-additional-rbac-asi-def-loop.bicep' = [ +module managementGroupRoleAssignments 'management-group-additional-rbac-asi-def-loop.bicep' = [ for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && !empty(additionalManagementGroupsIDsToAssignRbacTo) && identity == 'SystemAssigned') { name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC' params: { name: name policyAssignmentIdentityId: policyAssignment.identity.principalId roleDefinitionId: roleDefinitionId - additionalManagementGroupsIDsToAssignRbacTo: additionalManagementGroupsIDsToAssignRbacTo + managementGroupsIDsToAssignRbacTo: finalArrayOfManagementGroupsToAssignRbacTo } } ] From 7c22f88710293a1d25facd08e2f6ebab261fbfa5 Mon Sep 17 00:00:00 2001 From: Jack Tracey Date: Sat, 30 Nov 2024 14:44:58 +0000 Subject: [PATCH 5/7] set-avmmodule --- .../authorization/policy-assignment/README.md | 9 + .../authorization/policy-assignment/main.json | 209 +++++++++++++++--- 2 files changed, 189 insertions(+), 29 deletions(-) diff --git a/avm/ptn/authorization/policy-assignment/README.md b/avm/ptn/authorization/policy-assignment/README.md index 072b3bbe2e..3586f04ad2 100644 --- a/avm/ptn/authorization/policy-assignment/README.md +++ b/avm/ptn/authorization/policy-assignment/README.md @@ -1167,6 +1167,7 @@ param userAssignedIdentityId = '' | Parameter | Type | Description | | :-- | :-- | :-- | +| [`additionalManagementGroupsIDsToAssignRbacTo`](#parameter-additionalmanagementgroupsidstoassignrbacto) | array | An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity. | | [`description`](#parameter-description) | string | This message will be part of response in case of policy violation. | | [`displayName`](#parameter-displayname) | string | The display name of the policy assignment. Maximum length is 128 characters. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | @@ -1199,6 +1200,14 @@ Specifies the ID of the policy definition or policy set definition being assigne - Required: Yes - Type: string +### Parameter: `additionalManagementGroupsIDsToAssignRbacTo` + +An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity. + +- Required: No +- Type: array +- Default: `[]` + ### Parameter: `description` This message will be part of response in case of policy violation. diff --git a/avm/ptn/authorization/policy-assignment/main.json b/avm/ptn/authorization/policy-assignment/main.json index a7296fd6f9..110784ed20 100644 --- a/avm/ptn/authorization/policy-assignment/main.json +++ b/avm/ptn/authorization/policy-assignment/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2876622926889063776" + "version": "0.31.92.45157", + "templateHash": "11930294311655684795" }, "name": "Policy Assignments (All scopes)", "description": "This module deploys a Policy Assignment at a Management Group, Subscription or Resource Group scope.", @@ -104,6 +104,13 @@ "description": "Optional. The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment." } }, + "additionalManagementGroupsIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity." + } + }, "subscriptionId": { "type": "string", "defaultValue": "", @@ -211,14 +218,14 @@ "value": "[parameters('enforcementMode')]" }, "notScopes": "[if(not(empty(parameters('notScopes'))), createObject('value', parameters('notScopes')), createObject('value', createArray()))]", - "managementGroupId": { - "value": "[parameters('managementGroupId')]" - }, "location": { "value": "[parameters('location')]" }, "overrides": "[if(not(empty(parameters('overrides'))), createObject('value', parameters('overrides')), createObject('value', createArray()))]", - "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', createArray()))]" + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', createArray()))]", + "additionalManagementGroupsIDsToAssignRbacTo": { + "value": "[parameters('additionalManagementGroupsIDsToAssignRbacTo')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", @@ -226,8 +233,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3257252324855693362" + "version": "0.31.92.45157", + "templateHash": "5042119714141428580" }, "name": "Policy Assignments (Management Group scope)", "description": "This module deploys a Policy Assignment at a Management Group scope.", @@ -295,6 +302,13 @@ "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." } }, + "additionalManagementGroupsIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity." + } + }, "metadata": { "type": "object", "defaultValue": {}, @@ -320,13 +334,6 @@ "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." } }, - "managementGroupId": { - "type": "string", - "defaultValue": "[managementGroup().name]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment." - } - }, "notScopes": { "type": "array", "defaultValue": [], @@ -357,7 +364,8 @@ } }, "variables": { - "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]", + "finalArrayOfManagementGroupsToAssignRbacTo": "[if(equals(parameters('identity'), 'SystemAssigned'), union(parameters('additionalManagementGroupsIDsToAssignRbacTo'), createArray(managementGroup().name)), createArray())]" }, "resources": [ { @@ -381,17 +389,160 @@ }, { "copy": { - "name": "roleAssignment", + "name": "managementGroupRoleAssignments", "count": "[length(parameters('roleDefinitionIds'))]" }, - "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('managementGroupId'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", + "condition": "[and(and(not(empty(parameters('roleDefinitionIds'))), not(empty(parameters('additionalManagementGroupsIDsToAssignRbacTo')))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-Additional-RBAC', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionIds')[copyIndex()], parameters('name')))]", + "location": "[deployment().location]", "properties": { - "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", - "principalId": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", - "principalType": "ServicePrincipal" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionIds')[copyIndex()]]" + }, + "managementGroupsIDsToAssignRbacTo": { + "value": "[variables('finalArrayOfManagementGroupsToAssignRbacTo')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.31.92.45157", + "templateHash": "11309645875744678880" + } + }, + "parameters": { + "managementGroupsIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "copy": { + "name": "additionalManagementGroupRoleAssignmentsPerMG", + "count": "[length(parameters('managementGroupsIDsToAssignRbacTo'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-Additional-RBAC', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionId'), parameters('name')))]", + "scope": "[format('Microsoft.Management/managementGroups/{0}', parameters('managementGroupsIDsToAssignRbacTo')[copyIndex()])]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[parameters('policyAssignmentIdentityId')]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.31.92.45157", + "templateHash": "3019736989546376452" + } + }, + "parameters": { + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(managementGroup().id, parameters('roleDefinitionId'), parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('policyAssignmentIdentityId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + } + } + ] + } }, "dependsOn": [ "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name'))]" @@ -481,8 +632,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3684200367628760752" + "version": "0.31.92.45157", + "templateHash": "11837811199926553363" }, "name": "Policy Assignments (Subscription scope)", "description": "This module deploys a Policy Assignment at a Subscription scope.", @@ -736,8 +887,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3879842459774615474" + "version": "0.31.92.45157", + "templateHash": "14180900151844687910" }, "name": "Policy Assignments (Resource Group scope)", "description": "This module deploys a Policy Assignment at a Resource Group scope.", @@ -986,4 +1137,4 @@ "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value))]" } } -} \ No newline at end of file +} From 1195e8748089b912eca8123af7481d5f92c89d31 Mon Sep 17 00:00:00 2001 From: Jack Tracey Date: Sat, 30 Nov 2024 14:47:35 +0000 Subject: [PATCH 6/7] set-avmmodule --- avm/ptn/authorization/policy-assignment/main.json | 2 +- avm/ptn/authorization/policy-assignment/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/avm/ptn/authorization/policy-assignment/main.json b/avm/ptn/authorization/policy-assignment/main.json index 110784ed20..165a0150f0 100644 --- a/avm/ptn/authorization/policy-assignment/main.json +++ b/avm/ptn/authorization/policy-assignment/main.json @@ -1137,4 +1137,4 @@ "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value))]" } } -} +} \ No newline at end of file diff --git a/avm/ptn/authorization/policy-assignment/version.json b/avm/ptn/authorization/policy-assignment/version.json index 8def869ede..daf1a794d9 100644 --- a/avm/ptn/authorization/policy-assignment/version.json +++ b/avm/ptn/authorization/policy-assignment/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] From 371c93acb1c25f993d120e410566eb982b9124a9 Mon Sep 17 00:00:00 2001 From: Jack Tracey Date: Sat, 30 Nov 2024 15:01:11 +0000 Subject: [PATCH 7/7] add new test --- avm/ptn/authorization/policy-assignment/README.md | 11 +++++++++++ .../tests/e2e/mg.max/main.test.bicep | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/avm/ptn/authorization/policy-assignment/README.md b/avm/ptn/authorization/policy-assignment/README.md index 3586f04ad2..67d28183ca 100644 --- a/avm/ptn/authorization/policy-assignment/README.md +++ b/avm/ptn/authorization/policy-assignment/README.md @@ -129,6 +129,9 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:' + ] description: '[Description] Policy Assignment at the management group scope' displayName: '[Display Name] Policy Assignment at the management group scope' enforcementMode: 'DoNotEnforce' @@ -217,6 +220,11 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:" + ] + }, "description": { "value": "[Description] Policy Assignment at the management group scope" }, @@ -325,6 +333,9 @@ using 'br/public:avm/ptn/authorization/policy-assignment:' param name = 'apamgmax001' param policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' // Non-required parameters +param additionalManagementGroupsIDsToAssignRbacTo = [ + '' +] param description = '[Description] Policy Assignment at the management group scope' param displayName = '[Display Name] Policy Assignment at the management group scope' param enforcementMode = 'DoNotEnforce' diff --git a/avm/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep b/avm/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep index df7f62a951..37f19104d3 100644 --- a/avm/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep +++ b/avm/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep @@ -18,6 +18,15 @@ param namePrefix string = '#_namePrefix_#' @description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment.') param subscriptionId string = '#_subscriptionId_#' +// ============ // +// Dependencies // +// ============ // + +resource additionalMg 'Microsoft.Management/managementGroups@2023-04-01' = { + scope: tenant() + name: '${uniqueString(deployment().name)}-additional-mg' +} + // ============== // // Test Execution // // ============== // @@ -34,6 +43,9 @@ module testDeployment '../../../main.bicep' = { identity: 'SystemAssigned' location: resourceLocation managementGroupId: last(split(managementGroup().id, '/')) + additionalManagementGroupsIDsToAssignRbacTo: [ + additionalMg.name + ] metadata: { category: 'Security' version: '1.0'