From 11aba421d9d824b9dc8ff5195e9f5e8688e775ce Mon Sep 17 00:00:00 2001 From: Collin Mezach Date: Wed, 9 Oct 2024 16:45:53 +0200 Subject: [PATCH] feat: `avm/res/Cdn/profile` Add managed identity (#3446) ## Add managed identity to CDN module This is my first contribution, i hope i'm doing it right :) - added functionality to enable a system-assigned managed identity or a user-assigned managed identity for the CDN Profile module. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cdn.profile](https://github.com/cmezach/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg)](https://github.com/cmezach/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Collin Mezach --- avm/res/cdn/profile/README.md | 41 ++++++++++++++++++ avm/res/cdn/profile/main.bicep | 30 +++++++++++++ avm/res/cdn/profile/main.json | 43 ++++++++++++++++++- .../cdn/profile/tests/e2e/afd/main.test.bicep | 3 ++ avm/res/cdn/profile/version.json | 2 +- 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index 0bd698095d..cdbbe70b4d 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -420,6 +420,9 @@ module profile 'br/public:avm/res/cdn/profile:' = { } ] location: 'global' + managedIdentities: { + systemAssigned: true + } originGroups: [ { loadBalancingSettings: { @@ -517,6 +520,11 @@ module profile 'br/public:avm/res/cdn/profile:' = { "location": { "value": "global" }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "originGroups": { "value": [ { @@ -608,6 +616,9 @@ param customDomains = [ } ] param location = 'global' +param managedIdentities = { + systemAssigned: true +} param originGroups = [ { loadBalancingSettings: { @@ -1153,6 +1164,7 @@ param originResponseTimeoutSeconds = 60 | [`endpointProperties`](#parameter-endpointproperties) | object | Endpoint properties (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/endpoints?pivots=deployment-language-bicep#endpointproperties for details). | | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`originResponseTimeoutSeconds`](#parameter-originresponsetimeoutseconds) | int | Send and receive timeout on forwarding request to the origin. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ruleSets`](#parameter-rulesets) | array | Array of rule set objects. | @@ -1281,6 +1293,34 @@ Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + ### Parameter: `originResponseTimeoutSeconds` Send and receive timeout on forwarding request to the origin. @@ -1501,6 +1541,7 @@ Endpoint tags. | `profileType` | string | The type of the CDN profile. | | `resourceGroupName` | string | The resource group where the CDN profile is deployed. | | `resourceId` | string | The resource ID of the CDN profile. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | | `uri` | string | The uri of the CDN profile endpoint. | ## Data Collection diff --git a/avm/res/cdn/profile/main.bicep b/avm/res/cdn/profile/main.bicep index 87323ba79f..2c30c0c2e2 100644 --- a/avm/res/cdn/profile/main.bicep +++ b/avm/res/cdn/profile/main.bicep @@ -55,6 +55,9 @@ param securityPolicies securityPolicyType = [] @description('Optional. Endpoint tags.') param tags object? +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + @description('Optional. The lock settings of the service.') param lock lockType @@ -105,6 +108,21 @@ var formattedRoleAssignments = [ }) ] +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { name: '46d3xbcp.res.cdn-profile.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' @@ -127,6 +145,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT resource profile 'Microsoft.Cdn/profiles@2023-05-01' = { name: name location: location + identity: identity sku: { name: sku } @@ -294,10 +313,21 @@ output endpointId string = !empty(endpointProperties) ? profile_endpoint.outputs @description('The uri of the CDN profile endpoint.') output uri string = !empty(endpointProperties) ? profile_endpoint.outputs.uri : '' +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = profile.?identity.?principalId ?? '' + // =============== // // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + import { associationsType } from 'securityPolicies/main.bicep' type securityPolicyType = { @description('Required. Name of the security policy.') diff --git a/avm/res/cdn/profile/main.json b/avm/res/cdn/profile/main.json index 169cee8564..479e17ece5 100644 --- a/avm/res/cdn/profile/main.json +++ b/avm/res/cdn/profile/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "18013902785904421717" + "templateHash": "14447016685732236984" }, "name": "CDN Profiles", "description": "This module deploys a CDN Profile.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "securityPolicyType": { "type": "array", "items": { @@ -281,6 +304,12 @@ "description": "Optional. Endpoint tags." } }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "lock": { "$ref": "#/definitions/lockType", "metadata": { @@ -319,7 +348,9 @@ "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, "resources": { "avmTelemetry": { @@ -347,6 +378,7 @@ "apiVersion": "2023-05-01", "name": "[parameters('name')]", "location": "[parameters('location')]", + "identity": "[variables('identity')]", "sku": { "name": "[parameters('sku')]" }, @@ -2411,6 +2443,13 @@ "description": "The uri of the CDN profile endpoint." }, "value": "[if(not(empty(parameters('endpointProperties'))), reference('profile_endpoint').outputs.uri.value, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('profile', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" } } } \ No newline at end of file diff --git a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep index 7fe9142055..66c9abbdfb 100644 --- a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep +++ b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep @@ -42,6 +42,9 @@ module testDeployment '../../../main.bicep' = [ name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { name: 'dep-${namePrefix}-test-${serviceShort}' + managedIdentities: { + systemAssigned: true + } location: 'global' originResponseTimeoutSeconds: 60 sku: 'Standard_AzureFrontDoor' diff --git a/avm/res/cdn/profile/version.json b/avm/res/cdn/profile/version.json index 9ed3662aba..35040975ae 100644 --- a/avm/res/cdn/profile/version.json +++ b/avm/res/cdn/profile/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.6", + "version": "0.7", "pathFilters": [ "./main.json" ]