From b32c089bc10657b62c1f6d73f87823f2e6977a9f Mon Sep 17 00:00:00 2001 From: Seif Bassem <38246040+sebassem@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:45:05 +0200 Subject: [PATCH] Subscription resource providers registration (#52) * add rp registration * typo * update readme * wording * update guid to ds resources * update cleanup workflow * updates * update output * testing * testing * update tests * update naming * update naming * update guid * adding params * check for empty providers array * update cleanup * add output message * update readme * adding default value * update outputs * update subscription parameter * testing emty array * testing * add dependsOn for vnet for VHC * Update main.bicep Co-authored-by: Jack Tracey <41163455+jtracey93@users.noreply.github.com> * Update main.bicep Co-authored-by: Jack Tracey <41163455+jtracey93@users.noreply.github.com> * pr comments * updates * revert testing * unregister features * update tests * auto create docs * add lock param * add lock * remove locks * conditional loop fix * trailing white space * testing * testing * Apply suggestions from code review * Update module-tests.yml * add more error handling * add logic for registering providers * testing * switch to write-host * testing * testing * revert write-host * update pester tests * update features statuses * readme updates * enhance tests for rbac consistency * typo on version number * adding additional feature in examples * add wording around empty array * revert version update to 1.4.1 * test typo * testing * update version * linting * bump version * linting * try again * minor fix * testing * testing * testing * testing * testing * testing * increase wait * testing * testing --------- Co-authored-by: Jack Tracey <41163455+jtracey93@users.noreply.github.com> Co-authored-by: Jack Tracey --- .github/workflows/module-tests.yml | 27 +- README.md | 3 +- ...le-5-Hub-and-Spoke-With-RP-registration.md | 188 +++++++++ docs/wiki/Examples.md | 3 +- main.bicep | 171 ++++++++ main.bicep.parameters.md | 204 +++++++--- .../.bicep/nested_roleAssignments.bicep | 70 ++++ .../userAssignedIdentity/README.md | 233 +++++++++++ .../userAssignedIdentity/deploy.bicep | 84 ++++ .../userAssignedIdentity/version.json | 7 + .../.parameters/min.parameters.json | 9 + .../.parameters/parameters.json | 9 + .../deploymentScripts/README.md | 380 ++++++++++++++++++ .../deploymentScripts/deploy.bicep | 156 +++++++ .../deploymentScripts/version.json | 4 + ...-RegisterSubscriptionResourceProviders.ps1 | 101 +++++ src/self/subResourceWrapper/deploy.bicep | 220 ++++++++++ src/self/subResourceWrapper/readme.md | 260 +++++++++--- tests/lz-vending/full.test.bicep | 21 + tests/pester/full.tests.ps1 | 47 ++- 20 files changed, 2065 insertions(+), 132 deletions(-) create mode 100644 docs/wiki/Example-5-Hub-and-Spoke-With-RP-registration.md create mode 100644 src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/.bicep/nested_roleAssignments.bicep create mode 100644 src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/README.md create mode 100644 src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/deploy.bicep create mode 100644 src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/version.json create mode 100644 src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/min.parameters.json create mode 100644 src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/parameters.json create mode 100644 src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/README.md create mode 100644 src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/deploy.bicep create mode 100644 src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/version.json create mode 100644 src/scripts/Invoke-RegisterSubscriptionResourceProviders.ps1 diff --git a/.github/workflows/module-tests.yml b/.github/workflows/module-tests.yml index af3b0889..08657e2a 100644 --- a/.github/workflows/module-tests.yml +++ b/.github/workflows/module-tests.yml @@ -59,7 +59,7 @@ jobs: } } New-AzManagementGroupDeployment @inputObject -Whatif - azPSVersion: "latest" + azPSVersion: "10.4.1" - name: Vend Subscriptions & Networking Scenarios (Deploy) id: vend @@ -80,7 +80,7 @@ jobs: $bicepDeployment = New-AzManagementGroupDeployment @inputObject $outputValue = $bicepDeployment.Outputs.createdSubId.Value "SUBID=$outputValue" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - azPSVersion: "latest" + azPSVersion: "10.4.1" - name: Pester Tests id: pester @@ -103,23 +103,36 @@ jobs: } $result = Invoke-Pester -Configuration $pesterConfiguration exit $result.FailedCount - azPSVersion: "latest" + azPSVersion: "10.4.1" - name: Cleanup Vended Subscription & Networking Scenarios id: cleanup-vend + if: always() uses: azure/powershell@v1 with: inlineScript: | # Resource Group Names + $subId = "${{ env.SUBID }}" $rsgHsName = "rsg-${{ env.ARM_LOCATION }}-net-hs-pr-${{ env.GH_PR_NUMBER }}" $rsgVwanName = "rsg-${{ env.ARM_LOCATION }}-net-vwan-pr-${{ env.GH_PR_NUMBER }}" $rsgNetworkWatcherName = "NetworkWatcherRG" + $guid = $subId.substring(0,8) + $rsgDeploymentScriptName = "rsg-${{ env.ARM_LOCATION }}-ds-pr-${{ env.GH_PR_NUMBER }}-$guid" + $allRoleAssignmentsSub = Get-AzRoleAssignment -Scope "/subscriptions/$subId" -ErrorAction SilentlyContinue + $rbacIdentitiyNotFoundToCleanupContributor = $allRoleAssignmentsSub | Where-Object { $_.ObjectType -eq "Unknown" -and $_.RoleDefinitionName -eq "Contributor" } Write-Host "Cleanup Vended Subscription Resources & Resource Groups..." -ForegroundColor Yellow Select-AzSubscription -SubscriptionId "${{ env.SUBID }}" Remove-AzResourceGroup -Name $rsgHsName -Force Remove-AzResourceGroup -Name $rsgVwanName -Force Remove-AzResourceGroup -Name $rsgNetworkWatcherName -Force + Remove-AzResourceGroup -Name $rsgDeploymentScriptName -Force + + Write-Host "Cleanup registered resource providers and features..." -ForegroundColor Yellow + Unregister-AzProviderFeature -FeatureName "ArcServerPrivateLinkPreview" -ProviderNamespace "Microsoft.HybridCompute" + Unregister-AzProviderFeature -FeatureName "AzureServicesVm" -ProviderNamespace "Microsoft.AVS" + Unregister-AzResourceProvider -ProviderNamespace "Microsoft.HybridCompute" + Unregister-AzResourceProvider -ProviderNamespace "Microsoft.AVS" Write-Host "Cleanup Hub Subscription Resources..." -ForegroundColor Yellow Select-AzSubscription -SubscriptionId "${{ env.SUB_HUB_ID }}" @@ -130,4 +143,10 @@ jobs: $hubVnetPeering = Get-AzVirtualNetworkPeering -ResourceGroupName "rsg-blzv-perm-hubs-001" -VirtualNetworkName "vnet-uksouth-hub-blzv" -Name * Remove-AzVirtualNetworkPeering -ResourceGroupName "rsg-blzv-perm-hubs-001" -VirtualNetworkName "vnet-uksouth-hub-blzv" -Name "$($hubVnetPeering.Name)" -Force Write-Host "Cleanup Hub Subscription Resources... Complete!" -ForegroundColor Green - azPSVersion: "latest" + + Write-Host "Cleanup Unknown Contributor RBAC Assignments on Sub Scope..." -ForegroundColor Yellow + foreach ($assignment in $rbacIdentitiyNotFoundToCleanupContributor) { + Remove-AzRoleAssignment -objectId $assignment.ObjectId -Scope $assignment.Scope -RoleDefinitionName $assignment.RoleDefinitionName + } + Write-Host "Cleanup Unknown Contributor RBAC Assignments on Sub Scope... Complete!" -ForegroundColor Green + azPSVersion: "10.4.1" diff --git a/README.md b/README.md index df39f5f7..ed042503 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,12 @@ This is currently split logically into the following capabilities: - Networking - deploy a Virtual Network with, optional: - Hub & spoke connectivity (peering to a hub Virtual Network) - Virtual WAN connectivity (peering to a Virtual Hub via a Virtual Hub Connection) - - Including support for connections to Virtual WAN Hubs with Routing Intent configured + - Including support for connections to Virtual WAN Hubs with Routing Intent configured - Link to existing DDoS Network Protection Plan - Specify Custom DNS Servers - Role assignments - Tags +- Resource providers and resource providers features registration > When creating Virtual Network peerings, be aware of the [limit of peerings per Virtual Network.](https://learn.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits?toc=%2Fazure%2Fvirtual-network%2Ftoc.json#azure-resource-manager-virtual-networking-limits) diff --git a/docs/wiki/Example-5-Hub-and-Spoke-With-RP-registration.md b/docs/wiki/Example-5-Hub-and-Spoke-With-RP-registration.md new file mode 100644 index 00000000..78666ec6 --- /dev/null +++ b/docs/wiki/Example-5-Hub-and-Spoke-With-RP-registration.md @@ -0,0 +1,188 @@ + +## Example 5 - Landing Zone (Subscription) with a spoke Virtual Network peered to a Hub Virtual Network and resource providers and features registration + +### Bicep Module Registry + +Here is a simple example Bicep file for deploying a landing zone (Subscription) with a spoke Virtual Network peered to a Hub Virtual Network, resource providers and features registration using the [Bicep Module Registry](https://github.com/Azure/bicep-registry-modules): + +> A resoure group gets created in the subscription with the format "rsg--ds-" hosting a deployment script and a user-assigned managed identity. This resource group needs to be manually deleted if not needed after the resource providers features registration process. +> +> The resource providers registration process is asynchronous as it might take extended periods of time to register. +> After a preview feature is registered in your subscription, you'll see one of two states: Registered or Pending. +> +>- For a preview feature that doesn't require approval, the state is Registered. +>- If a preview feature requires approval, the registration state is Pending. You must request approval from the Azure service offering the preview feature. Usually, you request access through a support ticket. + +```bicep +targetScope = 'managementGroup' + +@description('Specifies the location for resources.') +param location string = 'uksouth' + +module sub003 'br/public:lz/sub-vending:1.4.1' = { + name: 'sub-bicep-lz-vending-example-001' + params: { + subscriptionAliasEnabled: true + subscriptionBillingScope: '/providers/Microsoft.Billing/billingAccounts/1234567/enrollmentAccounts/123456' + subscriptionAliasName: 'sub-bicep-lz-vending-example-001' + subscriptionDisplayName: 'sub-bicep-lz-vending-example-001' + subscriptionTags: { + test: 'true' + } + subscriptionWorkload: 'Production' + subscriptionManagementGroupAssociationEnabled: true + subscriptionManagementGroupId: 'alz-landingzones-corp' + virtualNetworkEnabled: true + virtualNetworkLocation: location + virtualNetworkResourceGroupName: 'rsg-${location}-net-001' + virtualNetworkName: 'vnet-${location}-001' + virtualNetworkAddressSpace: [ + '10.0.0.0/16' + ] + virtualNetworkResourceGroupLockEnabled: false + virtualNetworkPeeringEnabled: true + hubNetworkResourceId: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rsg-uks-net-hub-001/providers/Microsoft.Network/virtualNetworks/vnet-uks-hub-001' + resourceProviders : { + 'Microsoft.Compute' : ['InGuestHotPatchVMPreview'] + 'Microsoft.AVS' : ['AzureServicesVm','ArcAutomatedOnboarding'] + } + } +} +``` + +### ARM JSON Parameter File + +Here is a simple example parameter file for deploying a landing zone (Subscription) with a spoke Virtual Network peered to a Hub Virtual Network, resource providers and features registration: + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "subscriptionAliasEnabled": { + "value": true + }, + "subscriptionDisplayName": { + "value": "sub-bicep-lz-vending-example-001" + }, + "subscriptionAliasName": { + "value": "sub-bicep-lz-vending-example-001" + }, + "subscriptionBillingScope": { + "value": "providers/Microsoft.Billing/billingAccounts/1234567/enrollmentAccounts/123456" + }, + "subscriptionWorkload": { + "value": "Production" + }, + "existingSubscriptionId": { + "value": "" + }, + "subscriptionManagementGroupAssociationEnabled": { + "value": true + }, + "subscriptionManagementGroupId": { + "value": "alz-landingzones-corp" + }, + "subscriptionTags": { + "value": { + "Cost-Center": "ABC123", + "Usage": "Example" + } + }, + "virtualNetworkEnabled": { + "value": true + }, + "virtualNetworkResourceGroupName": { + "value": "rg-networking-001" + }, + "virtualNetworkResourceGroupTags": { + "value": { + "Cost-Center": "ABC123", + "Usage": "Example", + "Managed-By": "Platform Team" + } + }, + "virtualNetworkResourceGroupLockEnabled": { + "value": true + }, + "virtualNetworkLocation": { + "value": "uksouth" + }, + "virtualNetworkName": { + "value": "vnet-example-001" + }, + "virtualNetworkTags": { + "value": { + "Cost-Center": "ABC123", + "Usage": "Example", + "Managed-By": "Platform Team" + } + }, + "virtualNetworkAddressSpace": { + "value": [ + "10.0.0.0/16" + ] + }, + "virtualNetworkDnsServers": { + "value": [ + "10.4.1.4", + "10.2.1.5" + ] + }, + "virtualNetworkDdosPlanId": { + "value": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-hub-network-001/providers/Microsoft.Network/ddosProtectionPlans/ddos-001" + }, + "virtualNetworkPeeringEnabled": { + "value": true + }, + "hubNetworkResourceId": { + "value": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-hub-network-001/providers/Microsoft.Network/virtualNetworks/vnet-hub-001" + }, + "virtualNetworkUseRemoteGateways": { + "value": true + }, + "virtualNetworkVwanAssociatedRouteTableResourceId": { + "value": "" + }, + "virtualNetworkVwanPropagatedRouteTablesResourceIds": { + "value": [] + }, + "virtualNetworkVwanPropagatedLabels": { + "value": [] + }, + "roleAssignmentEnabled": { + "value": true + }, + "roleAssignments": { + "value": [ + { + "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "definition": "Contributor", + "relativeScope": "" + }, + { + "principalId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", + "definition": "/providers/Microsoft.Authorization/roleDefinitions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "relativeScope": "" + }, + { + "principalId": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz", + "definition": "Reader", + "relativeScope": "/resourceGroups/rg-networking-001" + } + ] + }, + "resourceProviders":{ + "value":{ + "Microsoft.Compute": ["InGuestHotPatchVMPreview"], + "Microsoft.AVS" : ["AzureServicesVm","ArcAutomatedOnboarding"] + } + }, + "disableTelemetry": { + "value": false + } + } +} +``` + +Back to [Examples](Examples) diff --git a/docs/wiki/Examples.md b/docs/wiki/Examples.md index 8d2fcbf1..8e09f8e0 100644 --- a/docs/wiki/Examples.md +++ b/docs/wiki/Examples.md @@ -5,9 +5,10 @@ Here are some example configurations that demonstrate the module usage. | Example | Description | | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| [Hub & Spoke](Example-1-Hub-and-Spoke) | Example of how to create a landing zone (Subscription) with with a spoke Virtual Network peered to a Hub Virtual Network | +| [Hub & Spoke](Example-1-Hub-and-Spoke) | Example of how to create a landing zone (Subscription) with a spoke Virtual Network peered to a Hub Virtual Network | | [Virtual WAN](Example-2-Virtual-WAN) | Example of how to create a landing zone (Subscription) with a spoke Virtual Network connected to a Virtual WAN Hub | | [Use with existing subscriptions](Example-3-Use-With-Existing-Subscriptions) | Example of how to use this module with existing landing zone Subscriptions | | [Multiple Virtual Networks in Single Subscription](Example-4-Multiple-VNets-In-Same-Subscription) | Example of how to create a landing zone (Subscription) with multiple spoke Virtual Networks | +| [Hub & Spoke with resource providers and resource providers features registration](Example-5-Hub-and-Spoke-With-RP-registration) | Example of how to create a landing zone (Subscription) with a spoke Virtual Network peered to a Hub Virtual Network, register resource providers and resource providers features | Before deploying, review the [Consumer Guide](https://github.com/azure/bicep-lz-vending/wiki/consumerguide) for guidance on how to consume this module. diff --git a/main.bicep b/main.bicep index 756213ef..ecf785bd 100644 --- a/main.bicep +++ b/main.bicep @@ -450,6 +450,166 @@ For more information on the telemetry collected by this module, that is controll ''') param disableTelemetry bool = false +@sys.description('Guid for the deployment script resources names based on subscription Id.') +var deploymentScriptResourcesSubGuid = substring((subscriptionAliasEnabled && empty(existingSubscriptionId)) ? createSubscription.outputs.subscriptionId : existingSubscriptionId,0,8) + +@sys.description('The name of the resource group to create the deployment script for resource providers registration.') +param deploymentScriptResourceGroupName string = 'rsg-${deployment().location}-ds' + +@sys.description('The name of the deployment script to register resource providers') +param deploymentScriptName string = 'ds-${deployment().location}' + +@sys.description('The name of the user managed identity for the resource providers registration deployment script.') +param deploymentScriptManagedIdentityName string = 'id-${deployment().location}' + + +@metadata({ + example: { + 'Microsoft.Compute' : ['InGuestHotPatchVMPreview'] + 'Microsoft.Storage' : [] + } + +}) +@sys.description(''' +An object of resource providers and resource providers features to register. If left blank/empty, a list of most common resource providers will be registered. + +- Type: `{}` Object +- Default value: `{ + 'Microsoft.ApiManagement' : [] + 'Microsoft.AppPlatform' : [] + 'Microsoft.Authorization' : [] + 'Microsoft.Automation' : [] + 'Microsoft.AVS' : [] + 'Microsoft.Blueprint' : [] + 'Microsoft.BotService' : [] + 'Microsoft.Cache' : [] + 'Microsoft.Cdn' : [] + 'Microsoft.CognitiveServices' : [] + 'Microsoft.Compute' : [] + 'Microsoft.ContainerInstance' : [] + 'Microsoft.ContainerRegistry' : [] + 'Microsoft.ContainerService' : [] + 'Microsoft.CostManagement' : [] + 'Microsoft.CustomProviders' : [] + 'Microsoft.Databricks' : [] + 'Microsoft.DataLakeAnalytics' : [] + 'Microsoft.DataLakeStore' : [] + 'Microsoft.DataMigration' : [] + 'Microsoft.DataProtection' : [] + 'Microsoft.DBforMariaDB' : [] + 'Microsoft.DBforMySQL' : [] + 'Microsoft.DBforPostgreSQL' : [] + 'Microsoft.DesktopVirtualization' : [] + 'Microsoft.Devices' : [] + 'Microsoft.DevTestLab' : [] + 'Microsoft.DocumentDB' : [] + 'Microsoft.EventGrid' : [] + 'Microsoft.EventHub' : [] + 'Microsoft.HDInsight' : [] + 'Microsoft.HealthcareApis' : [] + 'Microsoft.GuestConfiguration' : [] + 'Microsoft.KeyVault' : [] + 'Microsoft.Kusto' : [] + 'microsoft.insights' : [] + 'Microsoft.Logic' : [] + 'Microsoft.MachineLearningServices' : [] + 'Microsoft.Maintenance' : [] + 'Microsoft.ManagedIdentity' : [] + 'Microsoft.ManagedServices' : [] + 'Microsoft.Management' : [] + 'Microsoft.Maps' : [] + 'Microsoft.MarketplaceOrdering' : [] + 'Microsoft.Media' : [] + 'Microsoft.MixedReality' : [] + 'Microsoft.Network' : [] + 'Microsoft.NotificationHubs' : [] + 'Microsoft.OperationalInsights' : [] + 'Microsoft.OperationsManagement' : [] + 'Microsoft.PolicyInsights' : [] + 'Microsoft.PowerBIDedicated' : [] + 'Microsoft.Relay' : [] + 'Microsoft.RecoveryServices' : [] + 'Microsoft.Resources' : [] + 'Microsoft.Search' : [] + 'Microsoft.Security' : [] + 'Microsoft.SecurityInsights' : [] + 'Microsoft.ServiceBus' : [] + 'Microsoft.ServiceFabric' : [] + 'Microsoft.Sql' : [] + 'Microsoft.Storage' : [] + 'Microsoft.StreamAnalytics' : [] + 'Microsoft.TimeSeriesInsights' : [] + 'Microsoft.Web' : [] +}` +''') +param resourceProviders object = { + 'Microsoft.ApiManagement' : [] + 'Microsoft.AppPlatform' : [] + 'Microsoft.Authorization' : [] + 'Microsoft.Automation' : [] + 'Microsoft.AVS' : [] + 'Microsoft.Blueprint' : [] + 'Microsoft.BotService' : [] + 'Microsoft.Cache' : [] + 'Microsoft.Cdn' : [] + 'Microsoft.CognitiveServices' : [] + 'Microsoft.Compute' : [] + 'Microsoft.ContainerInstance' : [] + 'Microsoft.ContainerRegistry' : [] + 'Microsoft.ContainerService' : [] + 'Microsoft.CostManagement' : [] + 'Microsoft.CustomProviders' : [] + 'Microsoft.Databricks' : [] + 'Microsoft.DataLakeAnalytics' : [] + 'Microsoft.DataLakeStore' : [] + 'Microsoft.DataMigration' : [] + 'Microsoft.DataProtection' : [] + 'Microsoft.DBforMariaDB' : [] + 'Microsoft.DBforMySQL' : [] + 'Microsoft.DBforPostgreSQL' : [] + 'Microsoft.DesktopVirtualization' : [] + 'Microsoft.Devices' : [] + 'Microsoft.DevTestLab' : [] + 'Microsoft.DocumentDB' : [] + 'Microsoft.EventGrid' : [] + 'Microsoft.EventHub' : [] + 'Microsoft.HDInsight' : [] + 'Microsoft.HealthcareApis' : [] + 'Microsoft.GuestConfiguration' : [] + 'Microsoft.KeyVault' : [] + 'Microsoft.Kusto' : [] + 'microsoft.insights' : [] + 'Microsoft.Logic' : [] + 'Microsoft.MachineLearningServices' : [] + 'Microsoft.Maintenance' : [] + 'Microsoft.ManagedIdentity' : [] + 'Microsoft.ManagedServices' : [] + 'Microsoft.Management' : [] + 'Microsoft.Maps' : [] + 'Microsoft.MarketplaceOrdering' : [] + 'Microsoft.Media' : [] + 'Microsoft.MixedReality' : [] + 'Microsoft.Network' : [] + 'Microsoft.NotificationHubs' : [] + 'Microsoft.OperationalInsights' : [] + 'Microsoft.OperationsManagement' : [] + 'Microsoft.PolicyInsights' : [] + 'Microsoft.PowerBIDedicated' : [] + 'Microsoft.Relay' : [] + 'Microsoft.RecoveryServices' : [] + 'Microsoft.Resources' : [] + 'Microsoft.Search' : [] + 'Microsoft.Security' : [] + 'Microsoft.SecurityInsights' : [] + 'Microsoft.ServiceBus' : [] + 'Microsoft.ServiceFabric' : [] + 'Microsoft.Sql' : [] + 'Microsoft.Storage' : [] + 'Microsoft.StreamAnalytics' : [] + 'Microsoft.TimeSeriesInsights' : [] + 'Microsoft.Web' : [] +} + // VARIABLES var existingSubscriptionIDEmptyCheck = empty(existingSubscriptionId) ? 'No Subscription ID Provided' : existingSubscriptionId @@ -518,6 +678,10 @@ module createSubscriptionResources 'src/self/subResourceWrapper/deploy.bicep' = roleAssignmentEnabled: roleAssignmentEnabled roleAssignments: roleAssignments disableTelemetry: disableTelemetry + deploymentScriptResourceGroupName: '${deploymentScriptResourceGroupName}-${deploymentScriptResourcesSubGuid}' + deploymentScriptName: '${deploymentScriptName}-${deploymentScriptResourcesSubGuid}' + deploymentScriptManagedIdentityName: '${deploymentScriptManagedIdentityName}-${deploymentScriptResourcesSubGuid}' + resourceProviders: resourceProviders } } @@ -534,3 +698,10 @@ output subscriptionAcceptOwnershipState string = (subscriptionAliasEnabled && em @sys.description('The Subscription Ownership URL. Only used when creating MCA Subscriptions across tenants') output subscriptionAcceptOwnershipUrl string = (subscriptionAliasEnabled && empty(existingSubscriptionId) && !empty(subscriptionTenantId) && !empty(subscriptionOwnerId)) ? createSubscription.outputs.subscriptionAcceptOwnershipUrl : 'N/A' + +@sys.description('The resource providers that failed to register') +output failedResourceProviders string = !empty(resourceProviders) ? createSubscriptionResources.outputs.failedProviders : '' + +@sys.description('The resource providers features that failed to register') +output failedResourceProvidersFeatures string = !empty(resourceProviders) ? createSubscriptionResources.outputs.failedFeatures : '' + diff --git a/main.bicep.parameters.md b/main.bicep.parameters.md index 7442c4f1..550a48ef 100644 --- a/main.bicep.parameters.md +++ b/main.bicep.parameters.md @@ -2,12 +2,6 @@ This module is designed to accelerate deployment of landing zones (aka Subscriptions) within an Azure AD Tenant. -These are the input parameters for the Bicep module: [`main.bicep`](./main.bicep) - -This is the orchestration module that is used and called by a consumer of the module to deploy a Landing Zone Subscription and its associated resources, based on the parameter input values that are provided to it at deployment time. - -> For more information and examples please see the [wiki](https://github.com/Azure/bicep-lz-vending/wiki) - ## Parameters Parameter name | Required | Description @@ -44,6 +38,10 @@ vHubRoutingIntentEnabled | No | Indicates whether routing intent is enable roleAssignmentEnabled | No | Whether to create role assignments or not. If true, supply the array of role assignment objects in the parameter called `roleAssignments`. - Type: Boolean roleAssignments | No | Supply an array of objects containing the details of the role assignments to create. Each object must contain the following `keys`: - `principalId` = The Object ID of the User, Group, SPN, Managed Identity to assign the RBAC role too. - `definition` = The Name of built-In RBAC Roles or a Resource ID of a Built-in or custom RBAC Role Definition. - `relativeScope` = 2 options can be provided for input value: 1. `''` *(empty string)* = Make RBAC Role Assignment to Subscription scope 2. `'/resourceGroups/'` = Make RBAC Role Assignment to specified Resource Group > See below [example in parameter file](#parameter-file) of various combinations - Type: `[]` Array - Default value: `[]` *(empty array)* disableTelemetry | No | Disable telemetry collection by this module. For more information on the telemetry collected by this module, that is controlled by this parameter, see this page in the wiki: [Telemetry Tracking Using Customer Usage Attribution (PID)](https://github.com/Azure/bicep-lz-vending/wiki/Telemetry) +deploymentScriptResourceGroupName | No | The name of the resource group to create the deployment script for resource providers registration. +deploymentScriptName | No | The name of the deployment script to register resource providers +deploymentScriptManagedIdentityName | No | The name of the user managed identity for the resource providers registration deployment script. +resourceProviders | No | An object of resource providers and resource providers features to register. If left blank/empty, a list of most common resource providers will be registered. - Type: `{}` Object - Default value: `{ 'Microsoft.ApiManagement' : [] 'Microsoft.AppPlatform' : [] 'Microsoft.Authorization' : [] 'Microsoft.Automation' : [] 'Microsoft.AVS' : [] 'Microsoft.Blueprint' : [] 'Microsoft.BotService' : [] 'Microsoft.Cache' : [] 'Microsoft.Cdn' : [] 'Microsoft.CognitiveServices' : [] 'Microsoft.Compute' : [] 'Microsoft.ContainerInstance' : [] 'Microsoft.ContainerRegistry' : [] 'Microsoft.ContainerService' : [] 'Microsoft.CostManagement' : [] 'Microsoft.CustomProviders' : [] 'Microsoft.Databricks' : [] 'Microsoft.DataLakeAnalytics' : [] 'Microsoft.DataLakeStore' : [] 'Microsoft.DataMigration' : [] 'Microsoft.DataProtection' : [] 'Microsoft.DBforMariaDB' : [] 'Microsoft.DBforMySQL' : [] 'Microsoft.DBforPostgreSQL' : [] 'Microsoft.DesktopVirtualization' : [] 'Microsoft.Devices' : [] 'Microsoft.DevTestLab' : [] 'Microsoft.DocumentDB' : [] 'Microsoft.EventGrid' : [] 'Microsoft.EventHub' : [] 'Microsoft.HDInsight' : [] 'Microsoft.HealthcareApis' : [] 'Microsoft.GuestConfiguration' : [] 'Microsoft.KeyVault' : [] 'Microsoft.Kusto' : [] 'microsoft.insights' : [] 'Microsoft.Logic' : [] 'Microsoft.MachineLearningServices' : [] 'Microsoft.Maintenance' : [] 'Microsoft.ManagedIdentity' : [] 'Microsoft.ManagedServices' : [] 'Microsoft.Management' : [] 'Microsoft.Maps' : [] 'Microsoft.MarketplaceOrdering' : [] 'Microsoft.Media' : [] 'Microsoft.MixedReality' : [] 'Microsoft.Network' : [] 'Microsoft.NotificationHubs' : [] 'Microsoft.OperationalInsights' : [] 'Microsoft.OperationsManagement' : [] 'Microsoft.PolicyInsights' : [] 'Microsoft.PowerBIDedicated' : [] 'Microsoft.Relay' : [] 'Microsoft.RecoveryServices' : [] 'Microsoft.Resources' : [] 'Microsoft.Search' : [] 'Microsoft.Security' : [] 'Microsoft.SecurityInsights' : [] 'Microsoft.ServiceBus' : [] 'Microsoft.ServiceFabric' : [] 'Microsoft.Sql' : [] 'Microsoft.Storage' : [] 'Microsoft.StreamAnalytics' : [] 'Microsoft.TimeSeriesInsights' : [] 'Microsoft.Web' : [] }` ### subscriptionAliasEnabled @@ -54,11 +52,7 @@ Whether to create a new Subscription using the Subscription Alias resource. If ` - Type: Boolean -**Default value** - -```text -True -``` +- Default value: `True` ### subscriptionDisplayName @@ -117,18 +111,9 @@ The workload type can be either `Production` or `DevTest` and is case sensitive. - Type: String -**Default value** - -```text -Production -``` - -**Allowed values** +- Default value: `Production` -```text -DevTest -Production -``` +- Allowed values: `DevTest`, `Production` ### subscriptionTenantId @@ -173,11 +158,7 @@ Whether to move the Subscription to the specified Management Group supplied in t - Type: Boolean -**Default value** - -```text -True -``` +- Default value: `True` ### subscriptionManagementGroupId @@ -224,11 +205,7 @@ If set to `true` ensure you also provide values for the following parameters at - Type: Boolean -**Default value** - -```text -False -``` +- Default value: `False` ### virtualNetworkResourceGroupName @@ -261,11 +238,7 @@ Enables the deployment of a `CanNotDelete` resource locks to the Virtual Network - Type: Boolean -**Default value** - -```text -True -``` +- Default value: `True` ### virtualNetworkLocation @@ -276,11 +249,7 @@ The location of the virtual network. Use region shortnames e.g. `uksouth`, `east - Type: String -**Default value** - -```text -[deployment().location] -``` +- Default value: `[deployment().location]` ### virtualNetworkName @@ -347,11 +316,7 @@ Whether to enable peering/connection with the supplied hub Virtual Network or Vi - Type: Boolean -**Default value** - -```text -False -``` +- Default value: `False` ### hubNetworkResourceId @@ -379,11 +344,7 @@ Enables the use of remote gateways in the specified hub virtual network. - Type: Boolean -**Default value** - -```text -True -``` +- Default value: `True` ### virtualNetworkVwanEnableInternetSecurity @@ -394,11 +355,7 @@ Enables the ability for the Virtual WAN Hub Connection to learn the default rout - Type: Boolean -**Default value** - -```text -True -``` +- Default value: `True` ### virtualNetworkVwanAssociatedRouteTableResourceId @@ -460,11 +417,7 @@ Whether to create role assignments or not. If true, supply the array of role ass - Type: Boolean -**Default value** - -```text -False -``` +- Default value: `False` ### roleAssignments @@ -494,11 +447,109 @@ Disable telemetry collection by this module. For more information on the telemetry collected by this module, that is controlled by this parameter, see this page in the wiki: [Telemetry Tracking Using Customer Usage Attribution (PID)](https://github.com/Azure/bicep-lz-vending/wiki/Telemetry) -**Default value** +- Default value: `False` -```text -False -``` +### deploymentScriptResourceGroupName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The name of the resource group to create the deployment script for resource providers registration. + +- Default value: `[format('rsg-{0}-ds', deployment().location)]` + +### deploymentScriptName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The name of the deployment script to register resource providers + +- Default value: `[format('ds-{0}', deployment().location)]` + +### deploymentScriptManagedIdentityName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The name of the user managed identity for the resource providers registration deployment script. + +- Default value: `[format('id-{0}', deployment().location)]` + +### resourceProviders + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +An object of resource providers and resource providers features to register. If left blank/empty, a list of most common resource providers will be registered. + +- Type: `{}` Object +- Default value: `{ + 'Microsoft.ApiManagement' : [] + 'Microsoft.AppPlatform' : [] + 'Microsoft.Authorization' : [] + 'Microsoft.Automation' : [] + 'Microsoft.AVS' : [] + 'Microsoft.Blueprint' : [] + 'Microsoft.BotService' : [] + 'Microsoft.Cache' : [] + 'Microsoft.Cdn' : [] + 'Microsoft.CognitiveServices' : [] + 'Microsoft.Compute' : [] + 'Microsoft.ContainerInstance' : [] + 'Microsoft.ContainerRegistry' : [] + 'Microsoft.ContainerService' : [] + 'Microsoft.CostManagement' : [] + 'Microsoft.CustomProviders' : [] + 'Microsoft.Databricks' : [] + 'Microsoft.DataLakeAnalytics' : [] + 'Microsoft.DataLakeStore' : [] + 'Microsoft.DataMigration' : [] + 'Microsoft.DataProtection' : [] + 'Microsoft.DBforMariaDB' : [] + 'Microsoft.DBforMySQL' : [] + 'Microsoft.DBforPostgreSQL' : [] + 'Microsoft.DesktopVirtualization' : [] + 'Microsoft.Devices' : [] + 'Microsoft.DevTestLab' : [] + 'Microsoft.DocumentDB' : [] + 'Microsoft.EventGrid' : [] + 'Microsoft.EventHub' : [] + 'Microsoft.HDInsight' : [] + 'Microsoft.HealthcareApis' : [] + 'Microsoft.GuestConfiguration' : [] + 'Microsoft.KeyVault' : [] + 'Microsoft.Kusto' : [] + 'microsoft.insights' : [] + 'Microsoft.Logic' : [] + 'Microsoft.MachineLearningServices' : [] + 'Microsoft.Maintenance' : [] + 'Microsoft.ManagedIdentity' : [] + 'Microsoft.ManagedServices' : [] + 'Microsoft.Management' : [] + 'Microsoft.Maps' : [] + 'Microsoft.MarketplaceOrdering' : [] + 'Microsoft.Media' : [] + 'Microsoft.MixedReality' : [] + 'Microsoft.Network' : [] + 'Microsoft.NotificationHubs' : [] + 'Microsoft.OperationalInsights' : [] + 'Microsoft.OperationsManagement' : [] + 'Microsoft.PolicyInsights' : [] + 'Microsoft.PowerBIDedicated' : [] + 'Microsoft.Relay' : [] + 'Microsoft.RecoveryServices' : [] + 'Microsoft.Resources' : [] + 'Microsoft.Search' : [] + 'Microsoft.Security' : [] + 'Microsoft.SecurityInsights' : [] + 'Microsoft.ServiceBus' : [] + 'Microsoft.ServiceFabric' : [] + 'Microsoft.Sql' : [] + 'Microsoft.Storage' : [] + 'Microsoft.StreamAnalytics' : [] + 'Microsoft.TimeSeriesInsights' : [] + 'Microsoft.Web' : [] +}` + + +- Default value: `@{Microsoft.ApiManagement=System.Object[]; Microsoft.AppPlatform=System.Object[]; Microsoft.Authorization=System.Object[]; Microsoft.Automation=System.Object[]; Microsoft.AVS=System.Object[]; Microsoft.Blueprint=System.Object[]; Microsoft.BotService=System.Object[]; Microsoft.Cache=System.Object[]; Microsoft.Cdn=System.Object[]; Microsoft.CognitiveServices=System.Object[]; Microsoft.Compute=System.Object[]; Microsoft.ContainerInstance=System.Object[]; Microsoft.ContainerRegistry=System.Object[]; Microsoft.ContainerService=System.Object[]; Microsoft.CostManagement=System.Object[]; Microsoft.CustomProviders=System.Object[]; Microsoft.Databricks=System.Object[]; Microsoft.DataLakeAnalytics=System.Object[]; Microsoft.DataLakeStore=System.Object[]; Microsoft.DataMigration=System.Object[]; Microsoft.DataProtection=System.Object[]; Microsoft.DBforMariaDB=System.Object[]; Microsoft.DBforMySQL=System.Object[]; Microsoft.DBforPostgreSQL=System.Object[]; Microsoft.DesktopVirtualization=System.Object[]; Microsoft.Devices=System.Object[]; Microsoft.DevTestLab=System.Object[]; Microsoft.DocumentDB=System.Object[]; Microsoft.EventGrid=System.Object[]; Microsoft.EventHub=System.Object[]; Microsoft.HDInsight=System.Object[]; Microsoft.HealthcareApis=System.Object[]; Microsoft.GuestConfiguration=System.Object[]; Microsoft.KeyVault=System.Object[]; Microsoft.Kusto=System.Object[]; microsoft.insights=System.Object[]; Microsoft.Logic=System.Object[]; Microsoft.MachineLearningServices=System.Object[]; Microsoft.Maintenance=System.Object[]; Microsoft.ManagedIdentity=System.Object[]; Microsoft.ManagedServices=System.Object[]; Microsoft.Management=System.Object[]; Microsoft.Maps=System.Object[]; Microsoft.MarketplaceOrdering=System.Object[]; Microsoft.Media=System.Object[]; Microsoft.MixedReality=System.Object[]; Microsoft.Network=System.Object[]; Microsoft.NotificationHubs=System.Object[]; Microsoft.OperationalInsights=System.Object[]; Microsoft.OperationsManagement=System.Object[]; Microsoft.PolicyInsights=System.Object[]; Microsoft.PowerBIDedicated=System.Object[]; Microsoft.Relay=System.Object[]; Microsoft.RecoveryServices=System.Object[]; Microsoft.Resources=System.Object[]; Microsoft.Search=System.Object[]; Microsoft.Security=System.Object[]; Microsoft.SecurityInsights=System.Object[]; Microsoft.ServiceBus=System.Object[]; Microsoft.ServiceFabric=System.Object[]; Microsoft.Sql=System.Object[]; Microsoft.Storage=System.Object[]; Microsoft.StreamAnalytics=System.Object[]; Microsoft.TimeSeriesInsights=System.Object[]; Microsoft.Web=System.Object[]}` ## Outputs @@ -508,6 +559,8 @@ subscriptionId | string | The Subscription ID that has been created or provided. subscriptionResourceId | string | The Subscription Resource ID that has been created or provided. subscriptionAcceptOwnershipState | string | The Subscription Owner State. Only used when creating MCA Subscriptions across tenants subscriptionAcceptOwnershipUrl | string | The Subscription Ownership URL. Only used when creating MCA Subscriptions across tenants +failedResourceProviders | string | The resource providers that failed to register +failedResourceProvidersFeatures | string | The resource providers features that failed to register ## Snippets @@ -518,7 +571,7 @@ subscriptionAcceptOwnershipUrl | string | The Subscription Ownership URL. Only u "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "metadata": { - "template": null + "template": "main.json" }, "parameters": { "subscriptionAliasEnabled": { @@ -658,6 +711,23 @@ subscriptionAcceptOwnershipUrl | string | The Subscription Ownership URL. Only u }, "disableTelemetry": { "value": false + }, + "deploymentScriptResourceGroupName": { + "value": "[format('rsg-{0}-ds', deployment().location)]" + }, + "deploymentScriptName": { + "value": "[format('ds-{0}', deployment().location)]" + }, + "deploymentScriptManagedIdentityName": { + "value": "[format('id-{0}', deployment().location)]" + }, + "resourceProviders": { + "value": { + "Microsoft.Compute": [ + "InGuestHotPatchVMPreview" + ], + "Microsoft.Storage": [] + } } } } diff --git a/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/.bicep/nested_roleAssignments.bicep b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/.bicep/nested_roleAssignments.bicep new file mode 100644 index 00000000..19a13565 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/.bicep/nested_roleAssignments.bicep @@ -0,0 +1,70 @@ +@sys.description('Required. The IDs of the principals to assign the role to.') +param principalIds array + +@sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') +param roleDefinitionIdOrName string + +@sys.description('Required. The resource ID of the resource to apply the role assignment to.') +param resourceId string + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') +param condition string = '' + +@sys.description('Optional. Version of the condition.') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. Id of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293') + 'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893') + 'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e') + 'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae') + 'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44') + 'Managed Identity Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59') + 'Managed Identity Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830') + 'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa') + 'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168') + 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') +} + +resource userMsi 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = { + name: last(split(resourceId, '/'))! +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: { + name: guid(userMsi.id, principalId, roleDefinitionIdOrName) + properties: { + description: description + roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName + principalId: principalId + principalType: !empty(principalType) ? any(principalType) : null + condition: !empty(condition) ? condition : null + conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) ? delegatedManagedIdentityResourceId : null + } + scope: userMsi +}] diff --git a/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/README.md b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/README.md new file mode 100644 index 00000000..3febcca6 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/README.md @@ -0,0 +1,233 @@ +# User Assigned Identities `[Microsoft.ManagedIdentity/userAssignedIdentities]` + +This module deploys a User Assigned Identity. + +## Navigation + +- [User Assigned Identities `[Microsoft.ManagedIdentity/userAssignedIdentities]`](#user-assigned-identities-microsoftmanagedidentityuserassignedidentities) + - [Navigation](#navigation) + - [Resource types](#resource-types) + - [Parameters](#parameters) + - [Optional parameters](#optional-parameters) + - [Parameter Usage: `roleAssignments`](#parameter-usage-roleassignments) + - [Parameter Usage: `tags`](#parameter-usage-tags) + - [Outputs](#outputs) + - [Cross-referenced modules](#cross-referenced-modules) + - [Deployment examples](#deployment-examples) + +## Resource types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.ManagedIdentity/userAssignedIdentities` | [2018-11-30](https://learn.microsoft.com/azure/templates/Microsoft.ManagedIdentity/2018-11-30/userAssignedIdentities) | + +## Parameters + +### Optional parameters + +| Parameter Name | Type | Default Value | Allowed Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). | +| `location` | string | `[resourceGroup().location]` | | Location for all resources. | +| `lock` | string | `''` | `['', CanNotDelete, ReadOnly]` | Specify the type of lock. | +| `name` | string | `[guid(resourceGroup().id)]` | | Name of the User Assigned Identity. | +| `roleAssignments` | array | `[]` | | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | +| `tags` | object | `{object}` | | Tags of the resource. | + +### Parameter Usage: `roleAssignments` + +Create a role assignment for the given resource. If you want to assign a service principal / managed identity that is created in the same deployment, make sure to also specify the `'principalType'` parameter and set it to `'ServicePrincipal'`. This will ensure the role assignment waits for the principal's propagation in Azure. + +
+ +Parameter JSON format + +```json +"roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "description": "Reader Role Assignment", + "principalIds": [ + "12345678-1234-1234-1234-123456789012", // object 1 + "78945612-1234-1234-1234-123456789012" // object 2 + ] + }, + { + "roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11", + "principalIds": [ + "12345678-1234-1234-1234-123456789012" // object 1 + ], + "principalType": "ServicePrincipal" + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + description: 'Reader Role Assignment' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + '78945612-1234-1234-1234-123456789012' // object 2 + ] + } + { + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' + principalIds: [ + '12345678-1234-1234-1234-123456789012' // object 1 + ] + principalType: 'ServicePrincipal' + } +] +``` + +
+

+ +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +

+ +Parameter JSON format + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +tags: { + Environment: 'Non-Prod' + Contact: 'test.user@testcompany.com' + PurchaseOrder: '1234' + CostCenter: '7890' + ServiceName: 'DeploymentValidation' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `clientId` | string | The client ID (application ID) of the user assigned identity. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the user assigned identity. | +| `principalId` | string | The principal ID (object ID) of the user assigned identity. | +| `resourceGroupName` | string | The resource group the user assigned identity was deployed into. | +| `resourceId` | string | The resource ID of the user assigned identity. | + +## Cross-referenced modules + +_None_ + +## Deployment examples + +The following module usage examples are retrieved from the content of the files hosted in the module's `.test` folder. + >**Note**: The name of each example is based on the name of the file from which it is taken. + >**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +

Example 1: Common

+ +
+ +via Bicep module + +```bicep +module userAssignedIdentity './managed-identity/user-assigned-identity/main.bicep' = { + name: '${uniqueString(deployment().name, location)}-test-miuaicom' + params: { + enableDefaultTelemetry: '' + lock: 'CanNotDelete' + name: 'miuaicom001' + roleAssignments: [ + { + principalIds: [ + '' + ] + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "enableDefaultTelemetry": { + "value": "" + }, + "lock": { + "value": "CanNotDelete" + }, + "name": { + "value": "miuaicom001" + }, + "roleAssignments": { + "value": [ + { + "principalIds": [ + "" + ], + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

diff --git a/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/deploy.bicep b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/deploy.bicep new file mode 100644 index 00000000..a4156a95 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/deploy.bicep @@ -0,0 +1,84 @@ +metadata name = 'User Assigned Identities' +metadata description = 'This module deploys a User Assigned Identity.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. Name of the User Assigned Identity.') +param name string = guid(resourceGroup().id) + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@allowed([ + '' + 'CanNotDelete' + 'ReadOnly' +]) +@description('Optional. Specify the type of lock.') +param lock string = '' + +@description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleAssignments array = [] + +@description('Optional. Tags of the resource.') +param tags object = {} + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource userMsi 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: name + location: location + tags: tags +} + +resource userMsi_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock)) { + name: '${userMsi.name}-${lock}-lock' + properties: { + level: any(lock) + notes: lock == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot modify the resource or child resources.' + } + scope: userMsi +} + +module userMsi_roleAssignments '.bicep/nested_roleAssignments.bicep' = [for (roleAssignment, index) in roleAssignments: { + name: '${uniqueString(deployment().name, location)}-UserMSI-Rbac-${index}' + params: { + description: contains(roleAssignment, 'description') ? roleAssignment.description : '' + principalIds: roleAssignment.principalIds + principalType: contains(roleAssignment, 'principalType') ? roleAssignment.principalType : '' + roleDefinitionIdOrName: roleAssignment.roleDefinitionIdOrName + condition: contains(roleAssignment, 'condition') ? roleAssignment.condition : '' + delegatedManagedIdentityResourceId: contains(roleAssignment, 'delegatedManagedIdentityResourceId') ? roleAssignment.delegatedManagedIdentityResourceId : '' + resourceId: userMsi.id + } +}] + +@description('The name of the user assigned identity.') +output name string = userMsi.name + +@description('The resource ID of the user assigned identity.') +output resourceId string = userMsi.id + +@description('The principal ID (object ID) of the user assigned identity.') +output principalId string = userMsi.properties.principalId + +@description('The client ID (application ID) of the user assigned identity.') +output clientId string = userMsi.properties.clientId + +@description('The resource group the user assigned identity was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = userMsi.location diff --git a/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/version.json b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/version.json new file mode 100644 index 00000000..96236a61 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} diff --git a/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/min.parameters.json b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/min.parameters.json new file mode 100644 index 00000000..57fa8566 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/min.parameters.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "<>-registerRPs" + } + } +} \ No newline at end of file diff --git a/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/parameters.json b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/parameters.json new file mode 100644 index 00000000..57fa8566 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/.parameters/parameters.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "<>-registerRPs" + } + } +} \ No newline at end of file diff --git a/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/README.md b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/README.md new file mode 100644 index 00000000..b6fdd340 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/README.md @@ -0,0 +1,380 @@ +# Deployment Scripts `[Microsoft.Resources/deploymentScripts]` + +This module deploys a Deployment Script. + +## Navigation + +- [Deployment Scripts `[Microsoft.Resources/deploymentScripts]`](#deployment-scripts-microsoftresourcesdeploymentscripts) + - [Navigation](#navigation) + - [Resource types](#resource-types) + - [Parameters](#parameters) + - [Parameter Usage: `tags`](#parameter-usage-tags) + - [Parameter Usage: `userAssignedIdentities`](#parameter-usage-userassignedidentities) + - [Outputs](#outputs) + - [Considerations](#considerations) + - [Cross-referenced modules](#cross-referenced-modules) + - [Deployment examples](#deployment-examples) + +## Resource types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Resources/deploymentScripts` | [2020-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2020-10-01/deploymentScripts) | + +## Parameters + +**Required parameters** + +| Parameter Name | Type | Description | +| :-- | :-- | :-- | +| `name` | string | Display name of the script to be run. | + +**Optional parameters** + +| Parameter Name | Type | Default Value | Allowed Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `arguments` | string | `''` | | Command-line arguments to pass to the script. Arguments are separated by spaces. | +| `azCliVersion` | string | `''` | | Azure CLI module version to be used. | +| `azPowerShellVersion` | string | `'3.0'` | | Azure PowerShell module version to be used. | +| `cleanupPreference` | string | `'Always'` | `[Always, OnExpiration, OnSuccess]` | The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled). | +| `containerGroupName` | string | `''` | | Container group name, if not specified then the name will get auto-generated. Not specifying a 'containerGroupName' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use 'containerGroupName' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. 'containerGroupName' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed. | +| `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). | +| `environmentVariables` | secureObject | `{object}` | | The environment variables to pass over to the script. The list is passed as an object with a key name "secureList" and the value is the list of environment variables (array). The list must have a 'name' and a 'value' or a 'secretValue' property for each object. | +| `kind` | string | `'AzurePowerShell'` | `[AzureCLI, AzurePowerShell]` | Type of the script. AzurePowerShell, AzureCLI. | +| `location` | string | `[resourceGroup().location]` | | Location for all resources. | +| `lock` | string | `''` | `['', CanNotDelete, ReadOnly]` | Specify the type of lock. | +| `primaryScriptUri` | string | `''` | | Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead. | +| `retentionInterval` | string | `'P1D'` | | Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week). | +| `runOnce` | bool | `False` | | When set to false, script will run every time the template is deployed. When set to true, the script will only run once. | +| `scriptContent` | string | `''` | | Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead. | +| `storageAccountResourceId` | string | `''` | | The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account. | +| `supportingScriptUris` | array | `[]` | | List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent). | +| `tags` | object | `{object}` | | Tags of the resource. | +| `timeout` | string | `'PT1H'` | | Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; 'PT30M' - 30 minutes; 'P5D' - 5 days; 'P1Y' 1 year. | +| `userAssignedIdentities` | object | `{object}` | | The ID(s) to assign to the resource. | + +**Generated parameters** + +| Parameter Name | Type | Default Value | Description | +| :-- | :-- | :-- | :-- | +| `baseTime` | string | `[utcNow('yyyy-MM-dd-HH-mm-ss')]` | Do not provide a value! This date value is used to make sure the script run every time the template is deployed. | + + +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +

+ +Parameter JSON format + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +tags: { + Environment: 'Non-Prod' + Contact: 'test.user@testcompany.com' + PurchaseOrder: '1234' + CostCenter: '7890' + ServiceName: 'DeploymentValidation' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Parameter Usage: `userAssignedIdentities` + +You can specify multiple user assigned identities to a resource by providing additional resource IDs using the following format: + +

+ +Parameter JSON format + +```json +"userAssignedIdentities": { + "value": { + "/subscriptions/[[subscriptionId]]/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-001": {}, + "/subscriptions/[[subscriptionId]]/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-002": {} + } +} +``` + +
+ +
+ +Bicep format + +```bicep +userAssignedIdentities: { + '/subscriptions/[[subscriptionId]]/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-001': {} + '/subscriptions/[[subscriptionId]]/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-sxx-az-msi-x-002': {} +} +``` + +
+

+ +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployment script. | +| `outputs` | object | The output of the deployment script. | +| `resourceGroupName` | string | The resource group the deployment script was deployed into. | +| `resourceId` | string | The resource ID of the deployment script. | + +## Considerations + +This module requires a User Assigned Identity (MSI, managed service identity) to exist, and this MSI has to have contributor rights on the subscription - that allows the Deployment Script to create the required Storage Account and the Azure Container Instance. + +## Cross-referenced modules + +_None_ + +## Deployment examples + +The following module usage examples are retrieved from the content of the files hosted in the module's `.test` folder. + >**Note**: The name of each example is based on the name of the file from which it is taken. + >**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +

Example 1: Cli

+ +
+ +via Bicep module + +```bicep +module deploymentScript './resources/deployment-script/main.bicep' = { + name: '${uniqueString(deployment().name, location)}-test-rdscli' + params: { + // Required parameters + name: 'rdscli001' + // Non-required parameters + azCliVersion: '2.40.0' + cleanupPreference: 'Always' + enableDefaultTelemetry: '' + environmentVariables: { + secureList: [ + { + name: 'var1' + value: 'test' + } + { + name: 'var2' + secureValue: '' + } + ] + } + kind: 'AzureCLI' + retentionInterval: 'P1D' + runOnce: false + scriptContent: 'echo \'echo echo echo\'' + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + timeout: 'PT30M' + userAssignedIdentities: { + '': {} + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "rdscli001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.40.0" + }, + "cleanupPreference": { + "value": "Always" + }, + "enableDefaultTelemetry": { + "value": "" + }, + "environmentVariables": { + "value": { + "secureList": [ + { + "name": "var1", + "value": "test" + }, + { + "name": "var2", + "secureValue": "" + } + ] + } + }, + "kind": { + "value": "AzureCLI" + }, + "retentionInterval": { + "value": "P1D" + }, + "runOnce": { + "value": false + }, + "scriptContent": { + "value": "echo \"echo echo echo\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + }, + "timeout": { + "value": "PT30M" + }, + "userAssignedIdentities": { + "value": { + "": {} + } + } + } +} +``` + +
+

+ +

Example 2: Ps

+ +
+ +via Bicep module + +```bicep +module deploymentScript './resources/deployment-script/main.bicep' = { + name: '${uniqueString(deployment().name, location)}-test-rdsps' + params: { + // Required parameters + name: 'rdsps001' + // Non-required parameters + azPowerShellVersion: '8.0' + cleanupPreference: 'Always' + enableDefaultTelemetry: '' + kind: 'AzurePowerShell' + lock: 'CanNotDelete' + retentionInterval: 'P1D' + runOnce: false + scriptContent: 'Write-Host \'The cake is a lie!\'' + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + timeout: 'PT30M' + userAssignedIdentities: { + '': {} + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "rdsps001" + }, + // Non-required parameters + "azPowerShellVersion": { + "value": "8.0" + }, + "cleanupPreference": { + "value": "Always" + }, + "enableDefaultTelemetry": { + "value": "" + }, + "kind": { + "value": "AzurePowerShell" + }, + "lock": { + "value": "CanNotDelete" + }, + "retentionInterval": { + "value": "P1D" + }, + "runOnce": { + "value": false + }, + "scriptContent": { + "value": "Write-Host \"The cake is a lie!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + }, + "timeout": { + "value": "PT30M" + }, + "userAssignedIdentities": { + "value": { + "": {} + } + } + } +} +``` + +
+

diff --git a/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/deploy.bicep b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/deploy.bicep new file mode 100644 index 00000000..fe29c5b5 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/deploy.bicep @@ -0,0 +1,156 @@ +metadata name = 'Deployment Scripts' +metadata description = 'This module deploys a Deployment Script.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Display name of the script to be run.') +param name string + +@description('Optional. The ID(s) to assign to the resource.') +param userAssignedIdentities object = {} + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Type of the script. AzurePowerShell, AzureCLI.') +@allowed([ + 'AzurePowerShell' + 'AzureCLI' +]) +param kind string = 'AzurePowerShell' + +@description('Optional. Azure PowerShell module version to be used.') +param azPowerShellVersion string = '3.0' + +@description('Optional. Azure CLI module version to be used.') +param azCliVersion string = '' + +@description('Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead.') +param scriptContent string = '' + +@description('Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent instead.') +param primaryScriptUri string = '' + +@description('Optional. The environment variables to pass over to the script. The list is passed as an object with a key name "secureList" and the value is the list of environment variables (array). The list must have a \'name\' and a \'value\' or a \'secretValue\' property for each object.') +@secure() +param environmentVariables object = {} + +@description('Optional. List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent).') +param supportingScriptUris array = [] + +@description('Optional. Command-line arguments to pass to the script. Arguments are separated by spaces.') +param arguments string = '' + +@description('Optional. Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week).') +param retentionInterval string = 'P1D' + +@description('Optional. When set to false, script will run every time the template is deployed. When set to true, the script will only run once.') +param runOnce bool = false + +@description('Optional. The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled).') +@allowed([ + 'Always' + 'OnSuccess' + 'OnExpiration' +]) +param cleanupPreference string = 'Always' + +@description('Optional. Container group name, if not specified then the name will get auto-generated. Not specifying a \'containerGroupName\' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use \'containerGroupName\' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. \'containerGroupName\' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed.') +param containerGroupName string = '' + +@description('Optional. The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account.') +param storageAccountResourceId string = '' + +@description('Optional. Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; \'PT30M\' - 30 minutes; \'P5D\' - 5 days; \'P1Y\' 1 year.') +param timeout string = 'PT1H' + +@description('Generated. Do not provide a value! This date value is used to make sure the script run every time the template is deployed.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@allowed([ + '' + 'CanNotDelete' + 'ReadOnly' +]) +@description('Optional. Specify the type of lock.') +param lock string = '' + +@description('Optional. Tags of the resource.') +param tags object = {} + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +var containerSettings = { + containerGroupName: containerGroupName +} + +var identityType = !empty(userAssignedIdentities) ? 'UserAssigned' : 'None' + +var identity = identityType != 'None' ? { + type: identityType + userAssignedIdentities: !empty(userAssignedIdentities) ? userAssignedIdentities : null +} : null + +var storageAccountSettings = !empty(storageAccountResourceId) ? { + storageAccountKey: listKeys(storageAccountResourceId, '2019-06-01').keys[0].value + storageAccountName: last(split(storageAccountResourceId, '/')) +} : {} + +resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: name + location: location + tags: tags + identity: identity + kind: any(kind) + properties: { + azPowerShellVersion: kind == 'AzurePowerShell' ? azPowerShellVersion : null + azCliVersion: kind == 'AzureCLI' ? azCliVersion : null + containerSettings: !empty(containerGroupName) ? containerSettings : null + storageAccountSettings: !empty(storageAccountResourceId) ? storageAccountSettings : null + arguments: arguments + environmentVariables: !empty(environmentVariables) ? environmentVariables.secureList : [] + scriptContent: !empty(scriptContent) ? scriptContent : null + primaryScriptUri: !empty(primaryScriptUri) ? primaryScriptUri : null + supportingScriptUris: !empty(supportingScriptUris) ? supportingScriptUris : null + cleanupPreference: cleanupPreference + forceUpdateTag: runOnce ? resourceGroup().name : baseTime + retentionInterval: retentionInterval + timeout: timeout + } +} + +resource deploymentScript_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock)) { + name: '${deploymentScript.name}-${lock}-lock' + properties: { + level: any(lock) + notes: lock == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot modify the resource or child resources.' + } + scope: deploymentScript +} + +@description('The resource ID of the deployment script.') +output resourceId string = deploymentScript.id + +@description('The resource group the deployment script was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the deployment script.') +output name string = deploymentScript.name + +@description('The location the resource was deployed into.') +output location string = deploymentScript.location + +@description('The output of the deployment script.') +output outputs object = contains(deploymentScript.properties, 'outputs') ? deploymentScript.properties.outputs : {} diff --git a/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/version.json b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/version.json new file mode 100644 index 00000000..98789666 --- /dev/null +++ b/src/carml/v0.6.0/Microsoft.Resources/deploymentScripts/version.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4" +} diff --git a/src/scripts/Invoke-RegisterSubscriptionResourceProviders.ps1 b/src/scripts/Invoke-RegisterSubscriptionResourceProviders.ps1 new file mode 100644 index 00000000..a1af1a42 --- /dev/null +++ b/src/scripts/Invoke-RegisterSubscriptionResourceProviders.ps1 @@ -0,0 +1,101 @@ +param( + [string]$subscriptionId, + [string]$resourceProviders +) + +$ErrorActionPreference = "SilentlyContinue" +# Selecting the right subscription +Select-AzSubscription -SubscriptionId $subscriptionId + +# Defining variables +$providers = $resourceProviders | ConvertFrom-Json -AsHashtable +$failedProviders = "" +$failedFeatures = "" +$DeploymentScriptOutputs = @{} + +############################################## +## Registering resource providers and features +############################################## + +if ($providers.Count -gt 0) { + foreach ($provider in $providers.keys) { + try { + # Registering resource providers + $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -eq $provider).registrationState + # Check if the providered is registered + if ($providerStatus -eq 'NotRegistered') { + Write-Output "`n Registering the '$provider' provider" + if (Register-AzResourceProvider -ProviderNamespace $provider) { + Write-Output "`n The registration for provider'$provider' has started successfully" + } + else { + Write-Output "`n The '$provider' provider has not been registered successfully" + $failedProviders += ",$provider" + } + } + elseif ($providerStatus -eq 'Registering') { + Write-Output "`n The '$provider' provider is in registering state" + $failedProviders += ",$provider" + } + + if ($failedProviders.length -gt 0) { + $output = $failedProviders.substring(1) + } + else { + $output = "No failures" + } + $DeploymentScriptOutputs["failedProvidersRegistrations"] = $output + } + catch { + Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" + $failedProviders += ",$provider" + if ($failedProviders.length -gt 0) { + $output = $failedProviders.substring(1) + } + $DeploymentScriptOutputs["failedProvidersRegistrations"] = $output + } + # Registering resource providers features + $features = $providers[$provider] + if ($features.length -gt 0) { + foreach ($feature in $features) { + try { + # Define variables + $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -eq $feature).RegistrationState + # Check if the feature is registered + if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') { + Write-Output "`n Registering the '$feature' feature" + if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) { + Write-Output "`n The The registration for feature '$feature' has started successfully" + } + else { + Write-Output "`n The '$feature' feature has not been registered successfully" + $failedFeatures += ",$feature" + } + } + elseif ($null -eq $featureStatus) { + Write-Output "`n The '$feature' feature doesn't exist." + $failedFeatures += ",$feature" + } + if ($failedFeatures.length -gt 0) { + $output = $failedFeatures.substring(1) + } + else { + $output = "No failures" + } + $DeploymentScriptOutputs["failedFeaturesRegistrations"] = $output + } + catch { + Write-Output "`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid" + $failedFeatures += ",$feature" + if ($failedFeatures.length -gt 0) { + $output = $failedFeatures.substring(1) + } + $DeploymentScriptOutputs["failedFeaturesRegistrations"] = $output + } + } + } + } +} +else { + Write-Output "`n No providers or features to register" +} diff --git a/src/self/subResourceWrapper/deploy.bicep b/src/self/subResourceWrapper/deploy.bicep index 710c06ef..4186bfd2 100644 --- a/src/self/subResourceWrapper/deploy.bicep +++ b/src/self/subResourceWrapper/deploy.bicep @@ -91,6 +91,159 @@ param roleAssignments array = [] @sys.description('Disable telemetry collection by this module. For more information on the telemetry collected by this module, that is controlled by this parameter, see this page in the wiki: [Telemetry Tracking Using Customer Usage Attribution (PID)](https://github.com/Azure/bicep-lz-vending/wiki/Telemetry)') param disableTelemetry bool = false +@maxLength(90) +@sys.description('The name of the resource group to create the deployment script for resource providers registration.') +param deploymentScriptResourceGroupName string + +@sys.description('The location of the deployment script. Use region shortnames e.g. uksouth, eastus, etc.') +param deploymentScriptLocation string = deployment().location + +@sys.description('The name of the deployment script to register resource providers') +param deploymentScriptName string + +@sys.description(''' +An object of resource providers and resource providers features to register. If left blank/empty, a list of most common resource providers will be registered. + +- Type: `{}` Object +- Default value: `{ + 'Microsoft.ApiManagement' : [] + 'Microsoft.AppPlatform' : [] + 'Microsoft.Authorization' : [] + 'Microsoft.Automation' : [] + 'Microsoft.AVS' : [] + 'Microsoft.Blueprint' : [] + 'Microsoft.BotService' : [] + 'Microsoft.Cache' : [] + 'Microsoft.Cdn' : [] + 'Microsoft.CognitiveServices' : [] + 'Microsoft.Compute' : [] + 'Microsoft.ContainerInstance' : [] + 'Microsoft.ContainerRegistry' : [] + 'Microsoft.ContainerService' : [] + 'Microsoft.CostManagement' : [] + 'Microsoft.CustomProviders' : [] + 'Microsoft.Databricks' : [] + 'Microsoft.DataLakeAnalytics' : [] + 'Microsoft.DataLakeStore' : [] + 'Microsoft.DataMigration' : [] + 'Microsoft.DataProtection' : [] + 'Microsoft.DBforMariaDB' : [] + 'Microsoft.DBforMySQL' : [] + 'Microsoft.DBforPostgreSQL' : [] + 'Microsoft.DesktopVirtualization' : [] + 'Microsoft.Devices' : [] + 'Microsoft.DevTestLab' : [] + 'Microsoft.DocumentDB' : [] + 'Microsoft.EventGrid' : [] + 'Microsoft.EventHub' : [] + 'Microsoft.HDInsight' : [] + 'Microsoft.HealthcareApis' : [] + 'Microsoft.GuestConfiguration' : [] + 'Microsoft.KeyVault' : [] + 'Microsoft.Kusto' : [] + 'microsoft.insights' : [] + 'Microsoft.Logic' : [] + 'Microsoft.MachineLearningServices' : [] + 'Microsoft.Maintenance' : [] + 'Microsoft.ManagedIdentity' : [] + 'Microsoft.ManagedServices' : [] + 'Microsoft.Management' : [] + 'Microsoft.Maps' : [] + 'Microsoft.MarketplaceOrdering' : [] + 'Microsoft.Media' : [] + 'Microsoft.MixedReality' : [] + 'Microsoft.Network' : [] + 'Microsoft.NotificationHubs' : [] + 'Microsoft.OperationalInsights' : [] + 'Microsoft.OperationsManagement' : [] + 'Microsoft.PolicyInsights' : [] + 'Microsoft.PowerBIDedicated' : [] + 'Microsoft.Relay' : [] + 'Microsoft.RecoveryServices' : [] + 'Microsoft.Resources' : [] + 'Microsoft.Search' : [] + 'Microsoft.Security' : [] + 'Microsoft.SecurityInsights' : [] + 'Microsoft.ServiceBus' : [] + 'Microsoft.ServiceFabric' : [] + 'Microsoft.Sql' : [] + 'Microsoft.Storage' : [] + 'Microsoft.StreamAnalytics' : [] + 'Microsoft.TimeSeriesInsights' : [] + 'Microsoft.Web' : [] +}` +''') +param resourceProviders object = { + 'Microsoft.ApiManagement' : [] + 'Microsoft.AppPlatform' : [] + 'Microsoft.Authorization' : [] + 'Microsoft.Automation' : [] + 'Microsoft.AVS' : [] + 'Microsoft.Blueprint' : [] + 'Microsoft.BotService' : [] + 'Microsoft.Cache' : [] + 'Microsoft.Cdn' : [] + 'Microsoft.CognitiveServices' : [] + 'Microsoft.Compute' : [] + 'Microsoft.ContainerInstance' : [] + 'Microsoft.ContainerRegistry' : [] + 'Microsoft.ContainerService' : [] + 'Microsoft.CostManagement' : [] + 'Microsoft.CustomProviders' : [] + 'Microsoft.Databricks' : [] + 'Microsoft.DataLakeAnalytics' : [] + 'Microsoft.DataLakeStore' : [] + 'Microsoft.DataMigration' : [] + 'Microsoft.DataProtection' : [] + 'Microsoft.DBforMariaDB' : [] + 'Microsoft.DBforMySQL' : [] + 'Microsoft.DBforPostgreSQL' : [] + 'Microsoft.DesktopVirtualization' : [] + 'Microsoft.Devices' : [] + 'Microsoft.DevTestLab' : [] + 'Microsoft.DocumentDB' : [] + 'Microsoft.EventGrid' : [] + 'Microsoft.EventHub' : [] + 'Microsoft.HDInsight' : [] + 'Microsoft.HealthcareApis' : [] + 'Microsoft.GuestConfiguration' : [] + 'Microsoft.KeyVault' : [] + 'Microsoft.Kusto' : [] + 'microsoft.insights' : [] + 'Microsoft.Logic' : [] + 'Microsoft.MachineLearningServices' : [] + 'Microsoft.Maintenance' : [] + 'Microsoft.ManagedIdentity' : [] + 'Microsoft.ManagedServices' : [] + 'Microsoft.Management' : [] + 'Microsoft.Maps' : [] + 'Microsoft.MarketplaceOrdering' : [] + 'Microsoft.Media' : [] + 'Microsoft.MixedReality' : [] + 'Microsoft.Network' : [] + 'Microsoft.NotificationHubs' : [] + 'Microsoft.OperationalInsights' : [] + 'Microsoft.OperationsManagement' : [] + 'Microsoft.PolicyInsights' : [] + 'Microsoft.PowerBIDedicated' : [] + 'Microsoft.Relay' : [] + 'Microsoft.RecoveryServices' : [] + 'Microsoft.Resources' : [] + 'Microsoft.Search' : [] + 'Microsoft.Security' : [] + 'Microsoft.SecurityInsights' : [] + 'Microsoft.ServiceBus' : [] + 'Microsoft.ServiceFabric' : [] + 'Microsoft.Sql' : [] + 'Microsoft.Storage' : [] + 'Microsoft.StreamAnalytics' : [] + 'Microsoft.TimeSeriesInsights' : [] + 'Microsoft.Web' : [] +} + +@sys.description('The name of the user managed identity for the resource providers registration deployment script.') +param deploymentScriptManagedIdentityName string + // VARIABLES // Deployment name variables @@ -105,6 +258,10 @@ var deploymentNames = { createLzRoleAssignmentsSub: take('lz-vend-rbac-sub-create-${uniqueString(subscriptionId, deployment().name)}', 64) createLzRoleAssignmentsRsgsSelf: take('lz-vend-rbac-rsg-self-create-${uniqueString(subscriptionId, deployment().name)}', 64) createLzRoleAssignmentsRsgsNotSelf: take('lz-vend-rbac-rsg-nself-create-${uniqueString(subscriptionId, deployment().name)}', 64) + createResourceGroupForDeploymentScript: take('lz-vend-rsg-ds-create-${uniqueString(subscriptionId, deploymentScriptResourceGroupName, deploymentScriptLocation, deployment().name)}', 64) + registerResourceProviders: take('lz-vend-ds-create-${uniqueString(subscriptionId, deployment().name)}', 64) + createDeploymentScriptManagedIdentity: take('lz-vend-ds-msi-create-${uniqueString(subscriptionId, deploymentScriptResourceGroupName, deployment().name)}', 64) + createRoleAssignmentsDeploymentScript: take('lz-vend-ds-rbac-create-${uniqueString(subscriptionId, deploymentScriptResourceGroupName, deploymentScriptManagedIdentityName, deployment().name)}', 64) } // Role Assignments filtering and splitting @@ -132,6 +289,8 @@ var virtualWanHubConnectionPropogatedLabels = !empty(virtualNetworkVwanPropagate // Telemetry for CARML flip var enableTelemetryForCarml = !disableTelemetry +var resourceProvidersFormatted = replace(string(resourceProviders), '"', '\\"') + // RESOURCES & MODULES module moveSubscriptionToManagementGroup '../Microsoft.Management/managementGroups/subscriptions/deploy.bicep' = if (subscriptionManagementGroupAssociationEnabled && !empty(subscriptionManagementGroupId)) { @@ -215,6 +374,7 @@ module createLzVnet '../../carml/v0.6.0/Microsoft.Network/virtualNetworks/deploy module createLzVirtualWanConnection '../../carml/v0.6.0/Microsoft.Network/virtualHubs/hubVirtualNetworkConnections/deploy.bicep' = if (virtualNetworkEnabled && virtualNetworkPeeringEnabled && !empty(virtualHubResourceIdChecked) && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName) && !empty(virtualWanHubResourceGroupName) && !empty(virtualWanHubSubscriptionId)) { dependsOn: [ createResourceGroupForLzNetworking + createLzVnet ] scope: resourceGroup(virtualWanHubSubscriptionId, virtualWanHubResourceGroupName) name: deploymentNames.createLzVirtualWanConnection @@ -274,4 +434,64 @@ module createLzRoleAssignmentsRsgsNotSelf '../../carml/v0.6.0/Microsoft.Authoriz } }] +module createResourceGroupForDeploymentScript '../../carml/v0.6.0/Microsoft.Resources/resourceGroups/deploy.bicep' = if (!empty(resourceProviders)) { + scope: subscription(subscriptionId) + name: deploymentNames.createResourceGroupForDeploymentScript + params: { + name: deploymentScriptResourceGroupName + location: deploymentScriptLocation + enableDefaultTelemetry: enableTelemetryForCarml + } +} + +module createManagedIdentityForDeploymentScript '../../carml/v0.6.0/Microsoft.ManagedIdentity/userAssignedIdentity/deploy.bicep' = if (!empty(resourceProviders)) { + scope: resourceGroup(subscriptionId,deploymentScriptResourceGroupName) + name: deploymentNames.createDeploymentScriptManagedIdentity + dependsOn: [ + createResourceGroupForDeploymentScript + ] + params:{ + location: deploymentScriptLocation + name: deploymentScriptManagedIdentityName + enableDefaultTelemetry: enableTelemetryForCarml + } +} + +module createRoleAssignmentsDeploymentScript '../../carml/v0.6.0/Microsoft.Authorization/roleAssignments/deploy.bicep' = if (!empty(resourceProviders)) { + dependsOn: [ + createManagedIdentityForDeploymentScript + ] + name: take('${deploymentNames.createRoleAssignmentsDeploymentScript}', 64) + params: { + location: deploymentScriptLocation + principalId: !empty(resourceProviders) ? createManagedIdentityForDeploymentScript.outputs.principalId : '' + roleDefinitionIdOrName: 'Contributor' + subscriptionId: subscriptionId + enableDefaultTelemetry: enableTelemetryForCarml + } +} + +module registerResourceProviders '../../carml/v0.6.0/Microsoft.Resources/deploymentScripts/deploy.bicep' = if (!empty(resourceProviders)) { + scope: resourceGroup(subscriptionId, deploymentScriptResourceGroupName) + name: deploymentNames.registerResourceProviders + params: { + name: deploymentScriptName + kind: 'AzurePowerShell' + azPowerShellVersion: '3.0' + cleanupPreference: 'Always' + enableDefaultTelemetry: enableTelemetryForCarml + location: deploymentScriptLocation + retentionInterval: 'P1D' + timeout: 'PT1H' + runOnce: true + userAssignedIdentities: !(empty(resourceProviders)) ? {'${createManagedIdentityForDeploymentScript.outputs.resourceId}': {}} : {} + arguments: '-resourceProviders \'${resourceProvidersFormatted}\' -resourceProvidersFeatures -subscriptionId ${subscriptionId}' + scriptContent: loadTextContent('../../scripts/Invoke-RegisterSubscriptionResourceProviders.ps1') + } +} + // OUTPUTS + +output failedProviders string = !empty(resourceProviders) ? registerResourceProviders.outputs.outputs['failedProvidersRegistrations'] : '' +output failedFeatures string = !empty(resourceProviders) ? registerResourceProviders.outputs.outputs['failedFeaturesRegistrations'] : '' + diff --git a/src/self/subResourceWrapper/readme.md b/src/self/subResourceWrapper/readme.md index 63ad4db9..93778fd0 100644 --- a/src/self/subResourceWrapper/readme.md +++ b/src/self/subResourceWrapper/readme.md @@ -2,12 +2,6 @@ This module is used by the [`bicep-lz-vending`](https://aka.ms/sub-vending/bicep) module to help orchestrate the deployment -These are the input parameters for the Bicep module: [`deploy.bicep`](./deploy.bicep) - -This is the sub-orchestration module that is used and called by the [`main.bicep`](../../../main.bicep) module to deploy the resources into the subscription that has been created (or an existing one provided), based on the parameter input values that are provided to it at deployment time from the `main.bicep` orchestration module. - -> ⚠️ It is not intended for this module to be called outside of being a sub-orchestration module for the `main.bicep` module ⚠️ - ## Parameters Parameter name | Required | Description @@ -36,6 +30,11 @@ virtualNetworkVwanPropagatedLabels | No | An array of virtual hub route ta roleAssignmentEnabled | No | Whether to create role assignments or not. If true, supply the array of role assignment objects in the parameter called `roleAssignments`. roleAssignments | No | Supply an array of objects containing the details of the role assignments to create. disableTelemetry | No | Disable telemetry collection by this module. For more information on the telemetry collected by this module, that is controlled by this parameter, see this page in the wiki: [Telemetry Tracking Using Customer Usage Attribution (PID)](https://github.com/Azure/bicep-lz-vending/wiki/Telemetry) +deploymentScriptResourceGroupName | Yes | The name of the resource group to create the deployment script for resource providers registration. +deploymentScriptLocation | No | The location of the deployment script. Use region shortnames e.g. uksouth, eastus, etc. +deploymentScriptName | Yes | The name of the deployment script to register resource providers +resourceProviders | No | An object of resource providers and resource providers features to register. If left blank/empty, a list of most common resource providers will be registered. - Type: `{}` Object - Default value: `{ 'Microsoft.ApiManagement' : [] 'Microsoft.AppPlatform' : [] 'Microsoft.Authorization' : [] 'Microsoft.Automation' : [] 'Microsoft.AVS' : [] 'Microsoft.Blueprint' : [] 'Microsoft.BotService' : [] 'Microsoft.Cache' : [] 'Microsoft.Cdn' : [] 'Microsoft.CognitiveServices' : [] 'Microsoft.Compute' : [] 'Microsoft.ContainerInstance' : [] 'Microsoft.ContainerRegistry' : [] 'Microsoft.ContainerService' : [] 'Microsoft.CostManagement' : [] 'Microsoft.CustomProviders' : [] 'Microsoft.Databricks' : [] 'Microsoft.DataLakeAnalytics' : [] 'Microsoft.DataLakeStore' : [] 'Microsoft.DataMigration' : [] 'Microsoft.DataProtection' : [] 'Microsoft.DBforMariaDB' : [] 'Microsoft.DBforMySQL' : [] 'Microsoft.DBforPostgreSQL' : [] 'Microsoft.DesktopVirtualization' : [] 'Microsoft.Devices' : [] 'Microsoft.DevTestLab' : [] 'Microsoft.DocumentDB' : [] 'Microsoft.EventGrid' : [] 'Microsoft.EventHub' : [] 'Microsoft.HDInsight' : [] 'Microsoft.HealthcareApis' : [] 'Microsoft.GuestConfiguration' : [] 'Microsoft.KeyVault' : [] 'Microsoft.Kusto' : [] 'microsoft.insights' : [] 'Microsoft.Logic' : [] 'Microsoft.MachineLearningServices' : [] 'Microsoft.Maintenance' : [] 'Microsoft.ManagedIdentity' : [] 'Microsoft.ManagedServices' : [] 'Microsoft.Management' : [] 'Microsoft.Maps' : [] 'Microsoft.MarketplaceOrdering' : [] 'Microsoft.Media' : [] 'Microsoft.MixedReality' : [] 'Microsoft.Network' : [] 'Microsoft.NotificationHubs' : [] 'Microsoft.OperationalInsights' : [] 'Microsoft.OperationsManagement' : [] 'Microsoft.PolicyInsights' : [] 'Microsoft.PowerBIDedicated' : [] 'Microsoft.Relay' : [] 'Microsoft.RecoveryServices' : [] 'Microsoft.Resources' : [] 'Microsoft.Search' : [] 'Microsoft.Security' : [] 'Microsoft.SecurityInsights' : [] 'Microsoft.ServiceBus' : [] 'Microsoft.ServiceFabric' : [] 'Microsoft.Sql' : [] 'Microsoft.Storage' : [] 'Microsoft.StreamAnalytics' : [] 'Microsoft.TimeSeriesInsights' : [] 'Microsoft.Web' : [] }` +deploymentScriptManagedIdentityName | Yes | The name of the user managed identity for the resource providers registration deployment script. ### subscriptionId @@ -49,11 +48,7 @@ disableTelemetry | No | Disable telemetry collection by this module. For m Whether to move the subscription to the specified management group supplied in the pararmeter subscriptionManagementGroupId. -**Default value** - -```text -True -``` +- Default value: `True` ### subscriptionManagementGroupId @@ -73,11 +68,7 @@ An object of tag key/value pairs to be appended to a subscription. NOTE: Tags wi Whether to create a virtual network or not. -**Default value** - -```text -False -``` +- Default value: `False` ### virtualNetworkResourceGroupName @@ -91,11 +82,7 @@ The name of the resource group to create the virtual network in. Enables the deployment of a `CanNotDelete` resource locks to the virtual networks resource group. -**Default value** - -```text -True -``` +- Default value: `True` ### virtualNetworkResourceGroupTags @@ -109,11 +96,7 @@ An object of tag key/value pairs to be appended to the Resource Group that the V The location of the virtual network. Use region shortnames e.g. uksouth, eastus, etc. -**Default value** - -```text -[deployment().location] -``` +- Default value: `[deployment().location]` ### virtualNetworkName @@ -151,11 +134,7 @@ The resoruce ID of an existing DDoS Network Protection Plan that you wish to lin Whether to enable peering/connection with the supplied hub virtual network or virtual hub. -**Default value** - -```text -False -``` +- Default value: `False` ### hubNetworkResourceId @@ -169,11 +148,7 @@ The resource ID of the virtual network or virtual wan hub in the hub to which th Enables the use of remote gateways in the spefcified hub virtual network. If no gateways exsit in the hub virtual network, set this to `false`, otherwise peering will fail to create. Set this to `false` for virtual wan hub connections. -**Default value** - -```text -True -``` +- Default value: `True` ### virtualNetworkVwanEnableInternetSecurity @@ -181,11 +156,7 @@ True Enables the ability for the Virtual WAN Hub Connection to learn the default route 0.0.0.0/0 from the Hub. -**Default value** - -```text -True -``` +- Default value: `True` ### virtualNetworkVwanAssociatedRouteTableResourceId @@ -211,11 +182,7 @@ An array of virtual hub route table labels to propogate routes to. If left blank Whether to create role assignments or not. If true, supply the array of role assignment objects in the parameter called `roleAssignments`. -**Default value** - -```text -False -``` +- Default value: `False` ### roleAssignments @@ -229,11 +196,118 @@ Supply an array of objects containing the details of the role assignments to cre Disable telemetry collection by this module. For more information on the telemetry collected by this module, that is controlled by this parameter, see this page in the wiki: [Telemetry Tracking Using Customer Usage Attribution (PID)](https://github.com/Azure/bicep-lz-vending/wiki/Telemetry) -**Default value** +- Default value: `False` -```text -False -``` +### deploymentScriptResourceGroupName + +![Parameter Setting](https://img.shields.io/badge/parameter-required-orange?style=flat-square) + +The name of the resource group to create the deployment script for resource providers registration. + +### deploymentScriptLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The location of the deployment script. Use region shortnames e.g. uksouth, eastus, etc. + +- Default value: `[deployment().location]` + +### deploymentScriptName + +![Parameter Setting](https://img.shields.io/badge/parameter-required-orange?style=flat-square) + +The name of the deployment script to register resource providers + +### resourceProviders + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +An object of resource providers and resource providers features to register. If left blank/empty, a list of most common resource providers will be registered.will be registered. + +- Type: `{}` Object +- Default value: `{ + 'Microsoft.ApiManagement' : [] + 'Microsoft.AppPlatform' : [] + 'Microsoft.Authorization' : [] + 'Microsoft.Automation' : [] + 'Microsoft.AVS' : [] + 'Microsoft.Blueprint' : [] + 'Microsoft.BotService' : [] + 'Microsoft.Cache' : [] + 'Microsoft.Cdn' : [] + 'Microsoft.CognitiveServices' : [] + 'Microsoft.Compute' : [] + 'Microsoft.ContainerInstance' : [] + 'Microsoft.ContainerRegistry' : [] + 'Microsoft.ContainerService' : [] + 'Microsoft.CostManagement' : [] + 'Microsoft.CustomProviders' : [] + 'Microsoft.Databricks' : [] + 'Microsoft.DataLakeAnalytics' : [] + 'Microsoft.DataLakeStore' : [] + 'Microsoft.DataMigration' : [] + 'Microsoft.DataProtection' : [] + 'Microsoft.DBforMariaDB' : [] + 'Microsoft.DBforMySQL' : [] + 'Microsoft.DBforPostgreSQL' : [] + 'Microsoft.DesktopVirtualization' : [] + 'Microsoft.Devices' : [] + 'Microsoft.DevTestLab' : [] + 'Microsoft.DocumentDB' : [] + 'Microsoft.EventGrid' : [] + 'Microsoft.EventHub' : [] + 'Microsoft.HDInsight' : [] + 'Microsoft.HealthcareApis' : [] + 'Microsoft.GuestConfiguration' : [] + 'Microsoft.KeyVault' : [] + 'Microsoft.Kusto' : [] + 'microsoft.insights' : [] + 'Microsoft.Logic' : [] + 'Microsoft.MachineLearningServices' : [] + 'Microsoft.Maintenance' : [] + 'Microsoft.ManagedIdentity' : [] + 'Microsoft.ManagedServices' : [] + 'Microsoft.Management' : [] + 'Microsoft.Maps' : [] + 'Microsoft.MarketplaceOrdering' : [] + 'Microsoft.Media' : [] + 'Microsoft.MixedReality' : [] + 'Microsoft.Network' : [] + 'Microsoft.NotificationHubs' : [] + 'Microsoft.OperationalInsights' : [] + 'Microsoft.OperationsManagement' : [] + 'Microsoft.PolicyInsights' : [] + 'Microsoft.PowerBIDedicated' : [] + 'Microsoft.Relay' : [] + 'Microsoft.RecoveryServices' : [] + 'Microsoft.Resources' : [] + 'Microsoft.Search' : [] + 'Microsoft.Security' : [] + 'Microsoft.SecurityInsights' : [] + 'Microsoft.ServiceBus' : [] + 'Microsoft.ServiceFabric' : [] + 'Microsoft.Sql' : [] + 'Microsoft.Storage' : [] + 'Microsoft.StreamAnalytics' : [] + 'Microsoft.TimeSeriesInsights' : [] + 'Microsoft.Web' : [] +}` + + +- Default value: `@{Microsoft.ApiManagement=System.Object[]; Microsoft.AppPlatform=System.Object[]; Microsoft.Authorization=System.Object[]; Microsoft.Automation=System.Object[]; Microsoft.AVS=System.Object[]; Microsoft.Blueprint=System.Object[]; Microsoft.BotService=System.Object[]; Microsoft.Cache=System.Object[]; Microsoft.Cdn=System.Object[]; Microsoft.CognitiveServices=System.Object[]; Microsoft.Compute=System.Object[]; Microsoft.ContainerInstance=System.Object[]; Microsoft.ContainerRegistry=System.Object[]; Microsoft.ContainerService=System.Object[]; Microsoft.CostManagement=System.Object[]; Microsoft.CustomProviders=System.Object[]; Microsoft.Databricks=System.Object[]; Microsoft.DataLakeAnalytics=System.Object[]; Microsoft.DataLakeStore=System.Object[]; Microsoft.DataMigration=System.Object[]; Microsoft.DataProtection=System.Object[]; Microsoft.DBforMariaDB=System.Object[]; Microsoft.DBforMySQL=System.Object[]; Microsoft.DBforPostgreSQL=System.Object[]; Microsoft.DesktopVirtualization=System.Object[]; Microsoft.Devices=System.Object[]; Microsoft.DevTestLab=System.Object[]; Microsoft.DocumentDB=System.Object[]; Microsoft.EventGrid=System.Object[]; Microsoft.EventHub=System.Object[]; Microsoft.HDInsight=System.Object[]; Microsoft.HealthcareApis=System.Object[]; Microsoft.GuestConfiguration=System.Object[]; Microsoft.KeyVault=System.Object[]; Microsoft.Kusto=System.Object[]; microsoft.insights=System.Object[]; Microsoft.Logic=System.Object[]; Microsoft.MachineLearningServices=System.Object[]; Microsoft.Maintenance=System.Object[]; Microsoft.ManagedIdentity=System.Object[]; Microsoft.ManagedServices=System.Object[]; Microsoft.Management=System.Object[]; Microsoft.Maps=System.Object[]; Microsoft.MarketplaceOrdering=System.Object[]; Microsoft.Media=System.Object[]; Microsoft.MixedReality=System.Object[]; Microsoft.Network=System.Object[]; Microsoft.NotificationHubs=System.Object[]; Microsoft.OperationalInsights=System.Object[]; Microsoft.OperationsManagement=System.Object[]; Microsoft.PolicyInsights=System.Object[]; Microsoft.PowerBIDedicated=System.Object[]; Microsoft.Relay=System.Object[]; Microsoft.RecoveryServices=System.Object[]; Microsoft.Resources=System.Object[]; Microsoft.Search=System.Object[]; Microsoft.Security=System.Object[]; Microsoft.SecurityInsights=System.Object[]; Microsoft.ServiceBus=System.Object[]; Microsoft.ServiceFabric=System.Object[]; Microsoft.Sql=System.Object[]; Microsoft.Storage=System.Object[]; Microsoft.StreamAnalytics=System.Object[]; Microsoft.TimeSeriesInsights=System.Object[]; Microsoft.Web=System.Object[]}` + +### deploymentScriptManagedIdentityName + +![Parameter Setting](https://img.shields.io/badge/parameter-required-orange?style=flat-square) + +The name of the user managed identity for the resource providers registration deployment script. + +## Outputs + +Name | Type | Description +---- | ---- | ----------- +failedProviders | string | +failedFeatures | string | ## Snippets @@ -244,7 +318,7 @@ False "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "metadata": { - "template": null + "template": "src/self/subResourceWrapper/deploy.json" }, "parameters": { "subscriptionId": { @@ -271,6 +345,9 @@ False "virtualNetworkResourceGroupTags": { "value": {} }, + "virtualNetworkLocation": { + "value": "[deployment().location]" + }, "virtualNetworkName": { "value": "" }, @@ -315,6 +392,87 @@ False }, "disableTelemetry": { "value": false + }, + "deploymentScriptResourceGroupName": { + "value": "" + }, + "deploymentScriptLocation": { + "value": "[deployment().location]" + }, + "deploymentScriptName": { + "value": "" + }, + "resourceProviders": { + "value": { + "Microsoft.ApiManagement": [], + "Microsoft.AppPlatform": [], + "Microsoft.Authorization": [], + "Microsoft.Automation": [], + "Microsoft.AVS": [], + "Microsoft.Blueprint": [], + "Microsoft.BotService": [], + "Microsoft.Cache": [], + "Microsoft.Cdn": [], + "Microsoft.CognitiveServices": [], + "Microsoft.Compute": [], + "Microsoft.ContainerInstance": [], + "Microsoft.ContainerRegistry": [], + "Microsoft.ContainerService": [], + "Microsoft.CostManagement": [], + "Microsoft.CustomProviders": [], + "Microsoft.Databricks": [], + "Microsoft.DataLakeAnalytics": [], + "Microsoft.DataLakeStore": [], + "Microsoft.DataMigration": [], + "Microsoft.DataProtection": [], + "Microsoft.DBforMariaDB": [], + "Microsoft.DBforMySQL": [], + "Microsoft.DBforPostgreSQL": [], + "Microsoft.DesktopVirtualization": [], + "Microsoft.Devices": [], + "Microsoft.DevTestLab": [], + "Microsoft.DocumentDB": [], + "Microsoft.EventGrid": [], + "Microsoft.EventHub": [], + "Microsoft.HDInsight": [], + "Microsoft.HealthcareApis": [], + "Microsoft.GuestConfiguration": [], + "Microsoft.KeyVault": [], + "Microsoft.Kusto": [], + "microsoft.insights": [], + "Microsoft.Logic": [], + "Microsoft.MachineLearningServices": [], + "Microsoft.Maintenance": [], + "Microsoft.ManagedIdentity": [], + "Microsoft.ManagedServices": [], + "Microsoft.Management": [], + "Microsoft.Maps": [], + "Microsoft.MarketplaceOrdering": [], + "Microsoft.Media": [], + "Microsoft.MixedReality": [], + "Microsoft.Network": [], + "Microsoft.NotificationHubs": [], + "Microsoft.OperationalInsights": [], + "Microsoft.OperationsManagement": [], + "Microsoft.PolicyInsights": [], + "Microsoft.PowerBIDedicated": [], + "Microsoft.Relay": [], + "Microsoft.RecoveryServices": [], + "Microsoft.Resources": [], + "Microsoft.Search": [], + "Microsoft.Security": [], + "Microsoft.SecurityInsights": [], + "Microsoft.ServiceBus": [], + "Microsoft.ServiceFabric": [], + "Microsoft.Sql": [], + "Microsoft.Storage": [], + "Microsoft.StreamAnalytics": [], + "Microsoft.TimeSeriesInsights": [], + "Microsoft.Web": [] + } + }, + "deploymentScriptManagedIdentityName": { + "value": "" } } } diff --git a/tests/lz-vending/full.test.bicep b/tests/lz-vending/full.test.bicep index d68437c8..4dd09f0e 100644 --- a/tests/lz-vending/full.test.bicep +++ b/tests/lz-vending/full.test.bicep @@ -19,6 +19,9 @@ module createSub '../../main.bicep' = { subscriptionWorkload: 'Production' subscriptionManagementGroupAssociationEnabled: true subscriptionManagementGroupId: 'bicep-lz-vending-automation-child' + deploymentScriptResourceGroupName: 'rsg-${location}-ds-pr-${prNumber}' + deploymentScriptManagedIdentityName: 'id-${location}-pr-${prNumber}' + deploymentScriptName: 'ds-${location}-pr-${prNumber}' virtualNetworkEnabled: false roleAssignmentEnabled: true roleAssignments: [ @@ -28,6 +31,10 @@ module createSub '../../main.bicep' = { relativeScope: '' } ] + resourceProviders : { + 'Microsoft.HybridCompute': ['ArcServerPrivateLinkPreview'] + 'Microsoft.AVS': ['AzureServicesVm'] + } } } @@ -39,6 +46,9 @@ module hubSpoke '../../main.bicep' = { virtualNetworkEnabled: true virtualNetworkLocation: location virtualNetworkResourceGroupName: 'rsg-${location}-net-hs-pr-${prNumber}' + deploymentScriptResourceGroupName: 'rsg-${location}-ds-pr-${prNumber}' + deploymentScriptManagedIdentityName: 'id-${location}-pr-${prNumber}' + deploymentScriptName: 'ds-${location}-pr-${prNumber}' virtualNetworkName: 'vnet-${location}-hs-pr-${prNumber}' virtualNetworkAddressSpace: [ '10.100.0.0/16' @@ -55,6 +65,10 @@ module hubSpoke '../../main.bicep' = { relativeScope: '/resourceGroups/rsg-${location}-net-hs-pr-${prNumber}' } ] + resourceProviders : { + 'Microsoft.HybridCompute': ['ArcServerPrivateLinkPreview'] + 'Microsoft.AVS': ['AzureServicesVm'] + } } } @@ -66,6 +80,9 @@ module vwanSpoke '../../main.bicep' = { virtualNetworkEnabled: true virtualNetworkLocation: location virtualNetworkResourceGroupName: 'rsg-${location}-net-vwan-pr-${prNumber}' + deploymentScriptResourceGroupName: 'rsg-${location}-ds-pr-${prNumber}' + deploymentScriptManagedIdentityName: 'id-${location}-pr-${prNumber}' + deploymentScriptName: 'ds-${location}-pr-${prNumber}' virtualNetworkName: 'vnet-${location}-vwan-pr-${prNumber}' virtualNetworkAddressSpace: [ '10.200.0.0/16' @@ -73,6 +90,10 @@ module vwanSpoke '../../main.bicep' = { virtualNetworkResourceGroupLockEnabled: false virtualNetworkPeeringEnabled: true hubNetworkResourceId: '/subscriptions/e4e7395f-dc45-411e-b425-95f75e470e16/resourceGroups/rsg-blzv-perm-hubs-001/providers/Microsoft.Network/virtualHubs/vhub-uksouth-blzv' + resourceProviders :{ + 'Microsoft.HybridCompute': ['ArcServerPrivateLinkPreview'] + 'Microsoft.AVS': ['AzureServicesVm'] + } } } diff --git a/tests/pester/full.tests.ps1 b/tests/pester/full.tests.ps1 index 10296973..d8852ca6 100644 --- a/tests/pester/full.tests.ps1 +++ b/tests/pester/full.tests.ps1 @@ -45,23 +45,54 @@ Describe "Bicep Landing Zone (Sub) Vending Tests" { $mgAssociation = Get-AzManagementGroupSubscription -SubscriptionId $subId -GroupId "bicep-lz-vending-automation-child" -ErrorAction SilentlyContinue $mgAssociation.Id | Should -Be "/providers/Microsoft.Management/managementGroups/bicep-lz-vending-automation-child/subscriptions/$subId" } - } - Context "Role-Based Access Control Assignment Tests" { - BeforeAll { - $allRoleAssignmentsSub = Get-AzRoleAssignment -Scope "/subscriptions/$subId" -ErrorAction SilentlyContinue - $allRoleAssignmentsRsg = Get-AzRoleAssignment -Scope "/subscriptions/$subId/resourceGroups/rsg-$location-net-hs-pr-$prNumber" -ErrorAction SilentlyContinue + It "Should have the 'Microsoft.HybridCompute', 'Microsoft.AVS' resource providers and the 'AzureServicesVm', 'ArcServerPrivateLinkPreview' resource providers features registered" { + $resourceProviders = @( "Microsoft.HybridCompute", "Microsoft.AVS" ) + $resourceProvidersFeatures = @( "AzureServicesVm", "ArcServerPrivateLinkPreview" ) + ForEach ($provider in $resourceProviders) { + $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -eq $provider).registrationState + $providerStatus | Should -BeIn @('Registered', 'Registering') + } + + ForEach ($feature in $resourceProvidersFeatures) { + $providerFeatureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -eq $feature).registrationState + $providerFeatureStatus | Should -BeIn @('Registered', 'Registering', 'Pending') + } } + } + Context "Role-Based Access Control Assignment Tests" { It "Should Have a Role Assignment for an known AAD Group with the Reader role directly upon the Subscription" { - $roleAssignment = $allRoleAssignmentsSub | Where-Object { $_.ObjectId -eq "7eca0dca-6701-46f1-b7b6-8b424dab50b3" -and $_.RoleDefinitionName -eq "Reader" } + $iterationCount = 0 + do { + $roleAssignment = Get-AzRoleAssignment -Scope "/subscriptions/$subId" -RoleDefinitionName "Reader" -ObjectId "7eca0dca-6701-46f1-b7b6-8b424dab50b3" -ErrorAction SilentlyContinue + if ($null -eq $roleAssignment) { + Write-Host "Waiting for Subscription Role Assignments to be eventually consistent... Iteration: $($iterationCount)" -ForegroundColor Yellow + Start-Sleep -Seconds 30 + $iterationCount++ + } + } until ( + $roleAssignment -ne $null -or $iterationCount -ge 10 + ) + $roleAssignment.ObjectId | Should -Be "7eca0dca-6701-46f1-b7b6-8b424dab50b3" $roleAssignment.RoleDefinitionName | Should -Be "Reader" $roleAssignment.scope | Should -Be "/subscriptions/$subId" } It "Should Have a Role Assignment for an known AAD Group with the Network Contributor role directly upon the Resource Group" { - $roleAssignment = $allRoleAssignmentsRsg | Where-Object { $_.ObjectId -eq "7eca0dca-6701-46f1-b7b6-8b424dab50b3" -and $_.RoleDefinitionName -eq "Network Contributor" } + $iterationCount = 0 + do { + $roleAssignment = Get-AzRoleAssignment -Scope "/subscriptions/$subId/resourceGroups/rsg-$location-net-hs-pr-$prNumber" -RoleDefinitionName "Network Contributor" -ObjectId "7eca0dca-6701-46f1-b7b6-8b424dab50b3" -ErrorAction SilentlyContinue + if ($null -eq $roleAssignment) { + Write-Host "Waiting for Resource Group Role Assignments to be eventually consistent... Iteration: $($iterationCount)" -ForegroundColor Yellow + Start-Sleep -Seconds 30 + $iterationCount++ + } + } until ( + $roleAssignment -ne $null -or $iterationCount -ge 10 + ) + $roleAssignment.ObjectId | Should -Be "7eca0dca-6701-46f1-b7b6-8b424dab50b3" $roleAssignment.RoleDefinitionName | Should -Be "Network Contributor" $roleAssignment.scope | Should -Be "/subscriptions/$subId/resourceGroups/rsg-$location-net-hs-pr-$prNumber" @@ -195,7 +226,7 @@ Describe "Bicep Landing Zone (Sub) Vending Tests" { Context "Networking - Virtual WAN Hub Tests" { BeforeAll { - Select-AzSubscription -SubscriptionId e4e7395f-dc45-411e-b425-95f75e470e16 -ErrorAction Stop + Select-AzSubscription -SubscriptionId "e4e7395f-dc45-411e-b425-95f75e470e16" -ErrorAction Stop $vwanHub = $vwanHub = Get-AzVirtualHub -ResourceGroupName "rsg-blzv-perm-hubs-001" -Name "vhub-uksouth-blzv" -ErrorAction SilentlyContinue $vwanHubVhc = Get-AzVirtualHubVnetConnection -ResourceGroupName "rsg-blzv-perm-hubs-001" -VirtualHubName "vhub-uksouth-blzv" -Name * }